Bug 1431533: Part 1 - Cache module exports when a module is first loaded. r?mccr8 draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 18 Jan 2018 14:12:04 -0800
changeset 723880 1931e27261da728225533f66ce052eed1d5836b2
parent 721966 7d463ab1b36b77e34c6b0ea7910552038b4cb063
child 723881 9d054457dd2fed77b506fbbd98f1666887713ae8
push id96567
push usermaglione.k@gmail.com
push dateWed, 24 Jan 2018 00:47:30 +0000
reviewersmccr8
bugs1431533
milestone59.0a1
Bug 1431533: Part 1 - Cache module exports when a module is first loaded. r?mccr8 Looking up and copying exported properties each time a module is loaded is fairly expensive at the best of times. It's even more expensive when we only want to export a subset of symbols, which generally requires creating a temporary object to hold the exports, or fetching them directly from the returned global. Aside from making the general case a bit faster, storing exports on an object allows us to optimize lazy module imports by fetching imported symbols directly from the exports object with very little additional overhead. MozReview-Commit-ID: C9PGoXPNmsh
dom/base/ChromeUtils.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSComponentLoader.h
js/xpconnect/src/XPCComponents.cpp
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -397,18 +397,18 @@ ChromeUtils::Import(const GlobalObject& 
     targetObj.setObjectOrNull(aTargetObj.Value());
     optionalArgc = 1;
   } else {
     targetObj.setUndefined();
     optionalArgc = 0;
   }
 
   JS::Rooted<JS::Value> retval(cx);
-  nsresult rv = moduleloader->Import(registryLocation, targetObj, cx,
-                                     optionalArgc, &retval);
+  nsresult rv = moduleloader->ImportInto(registryLocation, targetObj, cx,
+                                         optionalArgc, &retval);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
   // Import() on the component loader can return NS_OK while leaving an
   // exception on the JSContext.  Check for that case.
   if (JS_IsExceptionPending(cx)) {
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -47,16 +47,17 @@
 #include "mozilla/AddonPathService.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 #include "mozilla/MacroForEach.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ScriptPreloader.h"
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/ResultExtensions.h"
 #include "mozilla/UniquePtrExtensions.h"
 #include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::scache;
 using namespace mozilla::loader;
 using namespace xpc;
 using namespace JS;
@@ -175,35 +176,16 @@ ReportOnCallerUTF8(JSContext* callerCont
     }
 
     JS_ReportErrorUTF8(callerContext, "%s", buf.get());
 
     va_end(ap);
     return NS_OK;
 }
 
-static nsresult
-MOZ_FORMAT_PRINTF(2, 3)
-ReportOnCallerUTF8(JSCLContextHelper& helper,
-                   const char* format, ...)
-{
-    va_list ap;
-    va_start(ap, format);
-
-    UniqueChars buf = JS_vsmprintf(format, ap);
-    if (!buf) {
-        va_end(ap);
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    helper.reportErrorAfterPop(Move(buf));
-    va_end(ap);
-    return NS_OK;
-}
-
 mozJSComponentLoader::mozJSComponentLoader()
     : mModules(16),
       mImports(16),
       mInProgressImports(16),
       mLocations(16),
       mInitialized(false),
       mShareLoaderGlobal(false),
       mLoaderGlobal(dom::RootingCx())
@@ -282,16 +264,35 @@ class MOZ_STACK_CLASS ComponentLoaderInf
   private:
     const nsACString& mLocation;
     nsCOMPtr<nsIIOService> mIOService;
     nsCOMPtr<nsIURI> mURI;
     nsCOMPtr<nsIChannel> mScriptChannel;
     nsCOMPtr<nsIURI> mResolvedURI;
 };
 
+template <typename ...Args>
+static nsresult
+ReportOnCallerUTF8(JSCLContextHelper& helper,
+                   const char* format,
+                   ComponentLoaderInfo& info,
+                   Args... args)
+{
+    nsCString location;
+    MOZ_TRY(info.GetLocation(location));
+
+    UniqueChars buf = JS_smprintf(format, location.get(), args...);
+    if (!buf) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    helper.reportErrorAfterPop(Move(buf));
+    return NS_ERROR_FAILURE;
+}
+
 #undef BEGIN_ENSURE
 #undef ENSURE_DEPS
 #undef ENSURE_DEP
 
 mozJSComponentLoader::~mozJSComponentLoader()
 {
     if (mInitialized) {
         NS_ERROR("'xpcom-shutdown-loaders' was not fired before cleaning up mozJSComponentLoader");
@@ -923,21 +924,21 @@ mozJSComponentLoader::UnloadModules()
 
     for (auto iter = mModules.Iter(); !iter.Done(); iter.Next()) {
         iter.Data()->Clear();
         iter.Remove();
     }
 }
 
 nsresult
-mozJSComponentLoader::Import(const nsACString& registryLocation,
-                             HandleValue targetValArg,
-                             JSContext* cx,
-                             uint8_t optionalArgc,
-                             MutableHandleValue retval)
+mozJSComponentLoader::ImportInto(const nsACString& registryLocation,
+                                 HandleValue targetValArg,
+                                 JSContext* cx,
+                                 uint8_t optionalArgc,
+                                 MutableHandleValue retval)
 {
     MOZ_ASSERT(nsContentUtils::IsCallerChrome());
 
     RootedValue targetVal(cx, targetValArg);
     RootedObject targetObject(cx, nullptr);
     if (optionalArgc) {
         // The caller passed in the optional second argument. Get it.
         if (targetVal.isObject()) {
@@ -1092,36 +1093,178 @@ ResolveModuleObjectPropertyById(JSContex
         }
     }
     return aModObj;
 }
 
 nsresult
 mozJSComponentLoader::ImportInto(const nsACString& aLocation,
                                  HandleObject targetObj,
-                                 JSContext* callercx,
+                                 JSContext* cx,
                                  MutableHandleObject vp)
 {
     vp.set(nullptr);
 
+    JS::RootedObject exports(cx);
+    MOZ_TRY(Import(cx, aLocation, vp, &exports, !targetObj));
+
+    if (targetObj) {
+        JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
+        if (!JS_Enumerate(cx, exports, &ids)) {
+            return NS_ERROR_OUT_OF_MEMORY;
+        }
+
+        JS::RootedValue value(cx);
+        JS::RootedId id(cx);
+        for (jsid idVal : ids) {
+            id = idVal;
+            if (!JS_GetPropertyById(cx, exports, id, &value) ||
+                !JS_SetPropertyById(cx, targetObj, id, value)) {
+                return NS_ERROR_FAILURE;
+            }
+        }
+    }
+
+    return NS_OK;
+}
+
+nsresult
+mozJSComponentLoader::ExtractExports(JSContext* aCx, ComponentLoaderInfo& aInfo,
+                                     ModuleEntry* aMod,
+                                     JS::MutableHandleObject aExports)
+{
+    // cxhelper must be created before jsapi, so that jsapi is destroyed and
+    // pops any context it has pushed before we report to the caller context.
+    JSCLContextHelper cxhelper(aCx);
+
+    // Even though we are calling JS_SetPropertyById on targetObj, we want
+    // to ensure that we never run script here, so we use an AutoJSAPI and
+    // not an AutoEntryScript.
+    dom::AutoJSAPI jsapi;
+    jsapi.Init();
+    JSContext* cx = jsapi.cx();
+    JSAutoCompartment ac(cx, aMod->obj);
+
+    RootedValue symbols(cx);
+    {
+        RootedObject obj(cx, ResolveModuleObjectProperty(cx, aMod->obj,
+                                                         "EXPORTED_SYMBOLS"));
+        if (!obj || !JS_GetProperty(cx, obj, "EXPORTED_SYMBOLS", &symbols)) {
+            return ReportOnCallerUTF8(cxhelper, ERROR_NOT_PRESENT, aInfo);
+        }
+    }
+
+    bool isArray;
+    if (!JS_IsArrayObject(cx, symbols, &isArray)) {
+        return NS_ERROR_FAILURE;
+    }
+    if (!isArray) {
+        return ReportOnCallerUTF8(cxhelper, ERROR_NOT_AN_ARRAY, aInfo);
+    }
+
+    RootedObject symbolsObj(cx, &symbols.toObject());
+
+    // Iterate over symbols array, installing symbols on targetObj:
+
+    uint32_t symbolCount = 0;
+    if (!JS_GetArrayLength(cx, symbolsObj, &symbolCount)) {
+        return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_ARRAY_LENGTH,
+                                  aInfo);
+    }
+
+#ifdef DEBUG
+    nsAutoCString logBuffer;
+#endif
+
+    aExports.set(JS_NewPlainObject(cx));
+    if (!aExports) {
+        return NS_ERROR_OUT_OF_MEMORY;
+    }
+
+    bool missing = false;
+
+    RootedValue value(cx);
+    RootedId symbolId(cx);
+    RootedObject symbolHolder(cx);
+    for (uint32_t i = 0; i < symbolCount; ++i) {
+        if (!JS_GetElement(cx, symbolsObj, i, &value) ||
+            !value.isString() ||
+            !JS_ValueToId(cx, value, &symbolId)) {
+            return ReportOnCallerUTF8(cxhelper, ERROR_ARRAY_ELEMENT, aInfo, i);
+        }
+
+        symbolHolder = ResolveModuleObjectPropertyById(cx, aMod->obj, symbolId);
+        if (!symbolHolder ||
+            !JS_GetPropertyById(cx, symbolHolder, symbolId, &value)) {
+            JSAutoByteString bytes;
+            RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
+            if (!bytes.encodeUtf8(cx, symbolStr))
+                return NS_ERROR_FAILURE;
+            return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_SYMBOL,
+                                      aInfo, bytes.ptr());
+        }
+
+        if (value.isUndefined()) {
+            missing = true;
+        }
+
+        if (!JS_SetPropertyById(cx, aExports, symbolId, value)) {
+            JSAutoByteString bytes;
+            RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
+            if (!bytes.encodeUtf8(cx, symbolStr))
+                return NS_ERROR_FAILURE;
+            return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_SYMBOL,
+                                      aInfo, bytes.ptr());
+        }
+#ifdef DEBUG
+        if (i == 0) {
+            logBuffer.AssignLiteral("Installing symbols [ ");
+        }
+        JSAutoByteString bytes(cx, JSID_TO_STRING(symbolId));
+        if (!!bytes)
+            logBuffer.Append(bytes.ptr());
+        logBuffer.Append(' ');
+        if (i == symbolCount - 1) {
+            nsCString location;
+            MOZ_TRY(aInfo.GetLocation(location));
+            LOG(("%s] from %s\n", logBuffer.get(), location.get()));
+        }
+#endif
+    }
+
+    // Don't cache the exports object if any of its exported symbols are
+    // missing. If the module hasn't finished loading yet, they may be
+    // defined the next time we try to import it.
+    if (!missing) {
+        aMod->exports = aExports;
+    }
+    return NS_OK;
+}
+
+nsresult
+mozJSComponentLoader::Import(JSContext* aCx, const nsACString& aLocation,
+                             JS::MutableHandleObject aModuleGlobal,
+                             JS::MutableHandleObject aModuleExports,
+                             bool aIgnoreExports)
+{
     nsresult rv;
     if (!mInitialized) {
         rv = ReallyInit();
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     ComponentLoaderInfo info(aLocation);
 
     rv = info.EnsureKey();
     NS_ENSURE_SUCCESS(rv, rv);
 
     ModuleEntry* mod;
     nsAutoPtr<ModuleEntry> newEntry;
     if (!mImports.Get(info.Key(), &mod) && !mInProgressImports.Get(info.Key(), &mod)) {
-        newEntry = new ModuleEntry(RootingContext::get(callercx));
+        newEntry = new ModuleEntry(RootingContext::get(aCx));
         if (!newEntry)
             return NS_ERROR_OUT_OF_MEMORY;
 
         rv = info.EnsureResolvedURI();
         NS_ENSURE_SUCCESS(rv, rv);
 
         // get the JAR if there is one
         nsCOMPtr<nsIJARURI> jarURI;
@@ -1152,166 +1295,59 @@ mozJSComponentLoader::ImportInto(const n
             return NS_ERROR_UNEXPECTED;
         }
 
         mLocations.Put(newEntry->resolvedURL, new nsCString(info.Key()));
         mInProgressImports.Put(info.Key(), newEntry);
 
         rv = info.EnsureURI();
         NS_ENSURE_SUCCESS(rv, rv);
-        RootedValue exception(callercx);
+        RootedValue exception(aCx);
         rv = ObjectForLocation(info, sourceFile, &newEntry->obj,
                                &newEntry->thisObjectKey,
                                &newEntry->location, true, &exception);
 
         mInProgressImports.Remove(info.Key());
 
         if (NS_FAILED(rv)) {
             if (!exception.isUndefined()) {
                 // An exception was thrown during compilation. Propagate it
                 // out to our caller so they can report it.
-                if (!JS_WrapValue(callercx, &exception))
+                if (!JS_WrapValue(aCx, &exception))
                     return NS_ERROR_OUT_OF_MEMORY;
-                JS_SetPendingException(callercx, exception);
-                return NS_OK;
+                JS_SetPendingException(aCx, exception);
+                return NS_ERROR_FAILURE;
             }
 
             // Something failed, but we don't know what it is, guess.
             return NS_ERROR_FILE_NOT_FOUND;
         }
 
 #ifdef STARTUP_RECORDER_ENABLED
         if (Preferences::GetBool("browser.startup.record", false)) {
             newEntry->importStack =
-                xpc_PrintJSStack(callercx, false, false, false).get();
+                xpc_PrintJSStack(aCx, false, false, false).get();
         }
 #endif
 
         mod = newEntry;
     }
 
     MOZ_ASSERT(mod->obj, "Import table contains entry with no object");
-    vp.set(mod->obj);
-
-    if (targetObj) {
-        // cxhelper must be created before jsapi, so that jsapi is destroyed and
-        // pops any context it has pushed before we report to the caller context.
-        JSCLContextHelper cxhelper(callercx);
-
-        // Even though we are calling JS_SetPropertyById on targetObj, we want
-        // to ensure that we never run script here, so we use an AutoJSAPI and
-        // not an AutoEntryScript.
-        dom::AutoJSAPI jsapi;
-        jsapi.Init();
-        JSContext* cx = jsapi.cx();
-        JSAutoCompartment ac(cx, mod->obj);
-
-        RootedValue symbols(cx);
-        RootedObject exportedSymbolsHolder(cx, ResolveModuleObjectProperty(cx, mod->obj,
-                                                                           "EXPORTED_SYMBOLS"));
-        if (!exportedSymbolsHolder ||
-            !JS_GetProperty(cx, exportedSymbolsHolder,
-                            "EXPORTED_SYMBOLS", &symbols)) {
-            nsCString location;
-            rv = info.GetLocation(location);
-            NS_ENSURE_SUCCESS(rv, rv);
-            return ReportOnCallerUTF8(cxhelper, ERROR_NOT_PRESENT,
-                                      location.get());
-        }
-
-        bool isArray;
-        if (!JS_IsArrayObject(cx, symbols, &isArray)) {
-            return NS_ERROR_FAILURE;
-        }
-        if (!isArray) {
-            nsCString location;
-            rv = info.GetLocation(location);
-            NS_ENSURE_SUCCESS(rv, rv);
-            return ReportOnCallerUTF8(cxhelper, ERROR_NOT_AN_ARRAY,
-                                      location.get());
-        }
-
-        RootedObject symbolsObj(cx, &symbols.toObject());
-
-        // Iterate over symbols array, installing symbols on targetObj:
-
-        uint32_t symbolCount = 0;
-        if (!JS_GetArrayLength(cx, symbolsObj, &symbolCount)) {
-            nsCString location;
-            rv = info.GetLocation(location);
-            NS_ENSURE_SUCCESS(rv, rv);
-            return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_ARRAY_LENGTH,
-                                      location.get());
-        }
-
-#ifdef DEBUG
-        nsAutoCString logBuffer;
-#endif
+    aModuleGlobal.set(mod->obj);
 
-        RootedValue value(cx);
-        RootedId symbolId(cx);
-        RootedObject symbolHolder(cx);
-        for (uint32_t i = 0; i < symbolCount; ++i) {
-            if (!JS_GetElement(cx, symbolsObj, i, &value) ||
-                !value.isString() ||
-                !JS_ValueToId(cx, value, &symbolId)) {
-                nsCString location;
-                rv = info.GetLocation(location);
-                NS_ENSURE_SUCCESS(rv, rv);
-                return ReportOnCallerUTF8(cxhelper, ERROR_ARRAY_ELEMENT,
-                                          location.get(), i);
-            }
-
-            symbolHolder = ResolveModuleObjectPropertyById(cx, mod->obj, symbolId);
-            if (!symbolHolder ||
-                !JS_GetPropertyById(cx, symbolHolder, symbolId, &value)) {
-                JSAutoByteString bytes;
-                RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
-                if (!bytes.encodeUtf8(cx, symbolStr))
-                    return NS_ERROR_FAILURE;
-                nsCString location;
-                rv = info.GetLocation(location);
-                NS_ENSURE_SUCCESS(rv, rv);
-                return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_SYMBOL,
-                                          location.get(), bytes.ptr());
-            }
-
-            JSAutoCompartment target_ac(cx, targetObj);
+    JS::RootedObject exports(aCx, mod->exports);
+    if (!exports && !aIgnoreExports) {
+        MOZ_TRY(ExtractExports(aCx, info, mod, &exports));
+    }
 
-            JS_MarkCrossZoneId(cx, symbolId);
-
-            if (!JS_WrapValue(cx, &value) ||
-                !JS_SetPropertyById(cx, targetObj, symbolId, value)) {
-                JSAutoByteString bytes;
-                RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
-                if (!bytes.encodeUtf8(cx, symbolStr))
-                    return NS_ERROR_FAILURE;
-                nsCString location;
-                rv = info.GetLocation(location);
-                NS_ENSURE_SUCCESS(rv, rv);
-                return ReportOnCallerUTF8(cxhelper, ERROR_SETTING_SYMBOL,
-                                          location.get(), bytes.ptr());
-            }
-#ifdef DEBUG
-            if (i == 0) {
-                logBuffer.AssignLiteral("Installing symbols [ ");
-            }
-            JSAutoByteString bytes(cx, JSID_TO_STRING(symbolId));
-            if (!!bytes)
-                logBuffer.Append(bytes.ptr());
-            logBuffer.Append(' ');
-            if (i == symbolCount - 1) {
-                nsCString location;
-                rv = info.GetLocation(location);
-                NS_ENSURE_SUCCESS(rv, rv);
-                LOG(("%s] from %s\n", logBuffer.get(), location.get()));
-            }
-#endif
-        }
+    if (exports && !JS_WrapObject(aCx, &exports)) {
+        return NS_ERROR_FAILURE;
     }
+    aModuleExports.set(exports);
 
     // Cache this module for later
     if (newEntry) {
         mImports.Put(info.Key(), newEntry);
         newEntry.forget();
     }
 
     return NS_OK;
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -57,18 +57,24 @@ class mozJSComponentLoader final : publi
 
     void FindTargetObject(JSContext* aCx,
                           JS::MutableHandleObject aTargetObject);
 
     static already_AddRefed<mozJSComponentLoader> GetOrCreate();
 
     static mozJSComponentLoader* Get() { return sSelf; }
 
-    nsresult Import(const nsACString& aResourceURI, JS::HandleValue aTargetObj,
-                    JSContext* aCx, uint8_t aArgc, JS::MutableHandleValue aRetval);
+    nsresult ImportInto(const nsACString& aResourceURI, JS::HandleValue aTargetObj,
+                        JSContext* aCx, uint8_t aArgc, JS::MutableHandleValue aRetval);
+
+    nsresult Import(JSContext* aCx, const nsACString& aResourceURI,
+                    JS::MutableHandleObject aModuleGlobal,
+                    JS::MutableHandleObject aModuleExports,
+                    bool aIgnoreExports = false);
+
     nsresult Unload(const nsACString& aResourceURI);
     nsresult IsModuleLoaded(const nsACString& aResourceURI, bool* aRetval);
     bool IsLoaderGlobal(JSObject* aObj) {
         return mLoaderGlobal == aObj;
     }
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
@@ -119,17 +125,18 @@ class mozJSComponentLoader final : publi
                         JS::MutableHandleObject vp);
 
     nsCOMPtr<nsIComponentManager> mCompMgr;
 
     class ModuleEntry : public mozilla::Module
     {
     public:
         explicit ModuleEntry(JS::RootingContext* aRootingCx)
-          : mozilla::Module(), obj(aRootingCx), thisObjectKey(aRootingCx)
+          : mozilla::Module(), obj(aRootingCx), exports(aRootingCx),
+            thisObjectKey(aRootingCx)
         {
             mVersion = mozilla::Module::kVersion;
             mCIDs = nullptr;
             mContractIDs = nullptr;
             mCategoryEntries = nullptr;
             getFactoryProc = GetFactory;
             loadProc = nullptr;
             unloadProc = nullptr;
@@ -169,24 +176,29 @@ class mozJSComponentLoader final : publi
 
         size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
         static already_AddRefed<nsIFactory> GetFactory(const mozilla::Module& module,
                                                        const mozilla::Module::CIDEntry& entry);
 
         nsCOMPtr<xpcIJSGetFactory> getfactoryobj;
         JS::PersistentRootedObject obj;
+        JS::PersistentRootedObject exports;
         JS::PersistentRootedScript thisObjectKey;
         char* location;
         nsCString resolvedURL;
 #ifdef STARTUP_RECORDER_ENABLED
         nsCString importStack;
 #endif
     };
 
+    nsresult ExtractExports(JSContext* aCx, ComponentLoaderInfo& aInfo,
+                            ModuleEntry* aMod,
+                            JS::MutableHandleObject aExports);
+
     static size_t DataEntrySizeOfExcludingThis(const nsACString& aKey, ModuleEntry* const& aData,
                                                mozilla::MallocSizeOf aMallocSizeOf, void* arg);
     static size_t ClassEntrySizeOfExcludingThis(const nsACString& aKey,
                                                 const nsAutoPtr<ModuleEntry>& aData,
                                                 mozilla::MallocSizeOf aMallocSizeOf, void* arg);
 
     // Modules are intentionally leaked, but still cleared.
     nsDataHashtable<nsCStringHashKey, ModuleEntry*> mModules;
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2289,17 +2289,17 @@ nsXPCComponents_Utils::Import(const nsAC
                               MutableHandleValue retval)
 {
     RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
     MOZ_ASSERT(moduleloader);
 
     AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING(
       "nsXPCComponents_Utils::Import", OTHER, registryLocation);
 
-    return moduleloader->Import(registryLocation, targetObj, cx, optionalArgc, retval);
+    return moduleloader->ImportInto(registryLocation, targetObj, cx, optionalArgc, retval);
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation, bool* retval)
 {
     RefPtr<mozJSComponentLoader> moduleloader = mozJSComponentLoader::Get();
     MOZ_ASSERT(moduleloader);
     return moduleloader->IsModuleLoaded(registryLocation, retval);