LCOV - code coverage report
Current view: top level - js/xpconnect/loader - mozJSComponentLoader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 348 553 62.9 %
Date: 2017-07-14 16:53:18 Functions: 31 47 66.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/Attributes.h"
       8             : 
       9             : #include <cstdarg>
      10             : 
      11             : #include "mozilla/Logging.h"
      12             : #ifdef ANDROID
      13             : #include <android/log.h>
      14             : #endif
      15             : #ifdef XP_WIN
      16             : #include <windows.h>
      17             : #endif
      18             : 
      19             : #include "jsapi.h"
      20             : #include "nsCOMPtr.h"
      21             : #include "nsAutoPtr.h"
      22             : #include "nsIComponentManager.h"
      23             : #include "mozilla/Module.h"
      24             : #include "nsIFile.h"
      25             : #include "mozJSComponentLoader.h"
      26             : #include "mozJSLoaderUtils.h"
      27             : #include "nsIXPConnect.h"
      28             : #include "nsIObserverService.h"
      29             : #include "nsIScriptSecurityManager.h"
      30             : #include "nsIFileURL.h"
      31             : #include "nsIJARURI.h"
      32             : #include "nsNetUtil.h"
      33             : #include "jsprf.h"
      34             : #include "nsJSPrincipals.h"
      35             : #include "nsJSUtils.h"
      36             : #include "xpcprivate.h"
      37             : #include "xpcpublic.h"
      38             : #include "nsContentUtils.h"
      39             : #include "nsXULAppAPI.h"
      40             : #include "GeckoProfiler.h"
      41             : #include "WrapperFactory.h"
      42             : 
      43             : #include "AutoMemMap.h"
      44             : #include "ScriptPreloader-inl.h"
      45             : 
      46             : #include "mozilla/AddonPathService.h"
      47             : #include "mozilla/scache/StartupCache.h"
      48             : #include "mozilla/scache/StartupCacheUtils.h"
      49             : #include "mozilla/MacroForEach.h"
      50             : #include "mozilla/Preferences.h"
      51             : #include "mozilla/ScriptPreloader.h"
      52             : #include "mozilla/dom/ScriptSettings.h"
      53             : #include "mozilla/UniquePtrExtensions.h"
      54             : #include "mozilla/Unused.h"
      55             : 
      56             : using namespace mozilla;
      57             : using namespace mozilla::scache;
      58             : using namespace mozilla::loader;
      59             : using namespace xpc;
      60             : using namespace JS;
      61             : 
      62             : static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
      63             : static const char kJSCachePrefix[] = "jsloader";
      64             : 
      65             : /**
      66             :  * Buffer sizes for serialization and deserialization of scripts.
      67             :  * FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008
      68             :  */
      69             : #define XPC_SERIALIZATION_BUFFER_SIZE   (64 * 1024)
      70             : #define XPC_DESERIALIZATION_BUFFER_SIZE (12 * 8192)
      71             : 
      72             : // MOZ_LOG=JSComponentLoader:5
      73             : static LazyLogModule gJSCLLog("JSComponentLoader");
      74             : 
      75             : #define LOG(args) MOZ_LOG(gJSCLLog, mozilla::LogLevel::Debug, args)
      76             : 
      77             : // Components.utils.import error messages
      78             : #define ERROR_SCOPE_OBJ "%s - Second argument must be an object."
      79             : #define ERROR_NOT_PRESENT "%s - EXPORTED_SYMBOLS is not present."
      80             : #define ERROR_NOT_AN_ARRAY "%s - EXPORTED_SYMBOLS is not an array."
      81             : #define ERROR_GETTING_ARRAY_LENGTH "%s - Error getting array length of EXPORTED_SYMBOLS."
      82             : #define ERROR_ARRAY_ELEMENT "%s - EXPORTED_SYMBOLS[%d] is not a string."
      83             : #define ERROR_GETTING_SYMBOL "%s - Could not get symbol '%s'."
      84             : #define ERROR_SETTING_SYMBOL "%s - Could not set symbol '%s' on target object."
      85             : 
      86             : static bool
      87           1 : Dump(JSContext* cx, unsigned argc, Value* vp)
      88             : {
      89           1 :     CallArgs args = CallArgsFromVp(argc, vp);
      90             : 
      91           1 :     if (args.length() == 0)
      92           0 :         return true;
      93             : 
      94           2 :     RootedString str(cx, JS::ToString(cx, args[0]));
      95           1 :     if (!str)
      96           0 :         return false;
      97             : 
      98           2 :     JSAutoByteString utf8str;
      99           1 :     if (!utf8str.encodeUtf8(cx, str))
     100           0 :         return false;
     101             : 
     102             : #ifdef ANDROID
     103             :     __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.ptr());
     104             : #endif
     105             : #ifdef XP_WIN
     106             :     if (IsDebuggerPresent()) {
     107             :         nsAutoJSString wstr;
     108             :         if (!wstr.init(cx, str))
     109             :             return false;
     110             :         OutputDebugStringW(wstr.get());
     111             :     }
     112             : #endif
     113           1 :     fputs(utf8str.ptr(), stdout);
     114           1 :     fflush(stdout);
     115           1 :     return true;
     116             : }
     117             : 
     118             : static bool
     119           0 : Debug(JSContext* cx, unsigned argc, Value* vp)
     120             : {
     121             : #ifdef DEBUG
     122           0 :     return Dump(cx, argc, vp);
     123             : #else
     124             :     return true;
     125             : #endif
     126             : }
     127             : 
     128             : static const JSFunctionSpec gGlobalFun[] = {
     129             :     JS_FS("dump",    Dump,   1,0),
     130             :     JS_FS("debug",   Debug,  1,0),
     131             :     JS_FS("atob",    Atob,   1,0),
     132             :     JS_FS("btoa",    Btoa,   1,0),
     133             :     JS_FS_END
     134             : };
     135             : 
     136             : class MOZ_STACK_CLASS JSCLContextHelper
     137             : {
     138             : public:
     139             :     explicit JSCLContextHelper(JSContext* aCx);
     140             :     ~JSCLContextHelper();
     141             : 
     142             :     void reportErrorAfterPop(UniqueChars&& buf);
     143             : 
     144             : private:
     145             :     JSContext* mContext;
     146             :     UniqueChars mBuf;
     147             : 
     148             :     // prevent copying and assignment
     149             :     JSCLContextHelper(const JSCLContextHelper&) = delete;
     150             :     const JSCLContextHelper& operator=(const JSCLContextHelper&) = delete;
     151             : };
     152             : 
     153             : static nsresult
     154             : MOZ_FORMAT_PRINTF(2, 3)
     155           0 : ReportOnCallerUTF8(JSContext* callerContext,
     156             :                    const char* format, ...) {
     157           0 :     if (!callerContext) {
     158           0 :         return NS_ERROR_FAILURE;
     159             :     }
     160             : 
     161             :     va_list ap;
     162           0 :     va_start(ap, format);
     163             : 
     164           0 :     UniqueChars buf = JS_vsmprintf(format, ap);
     165           0 :     if (!buf) {
     166           0 :         va_end(ap);
     167           0 :         return NS_ERROR_OUT_OF_MEMORY;
     168             :     }
     169             : 
     170           0 :     JS_ReportErrorUTF8(callerContext, "%s", buf.get());
     171             : 
     172           0 :     va_end(ap);
     173           0 :     return NS_OK;
     174             : }
     175             : 
     176             : static nsresult
     177             : MOZ_FORMAT_PRINTF(2, 3)
     178           0 : ReportOnCallerUTF8(JSCLContextHelper& helper,
     179             :                    const char* format, ...)
     180             : {
     181             :     va_list ap;
     182           0 :     va_start(ap, format);
     183             : 
     184           0 :     UniqueChars buf = JS_vsmprintf(format, ap);
     185           0 :     if (!buf) {
     186           0 :         va_end(ap);
     187           0 :         return NS_ERROR_OUT_OF_MEMORY;
     188             :     }
     189             : 
     190           0 :     helper.reportErrorAfterPop(Move(buf));
     191           0 :     va_end(ap);
     192           0 :     return NS_OK;
     193             : }
     194             : 
     195           3 : mozJSComponentLoader::mozJSComponentLoader()
     196             :     : mModules(16),
     197             :       mImports(16),
     198             :       mInProgressImports(16),
     199           3 :       mInitialized(false)
     200             : {
     201           3 :     MOZ_ASSERT(!sSelf, "mozJSComponentLoader should be a singleton");
     202             : 
     203           3 :     sSelf = this;
     204           3 : }
     205             : 
     206             : #define ENSURE_DEP(name) { nsresult rv = Ensure##name(); NS_ENSURE_SUCCESS(rv, rv); }
     207             : #define ENSURE_DEPS(...) MOZ_FOR_EACH(ENSURE_DEP, (), (__VA_ARGS__));
     208             : #define BEGIN_ENSURE(self, ...) { \
     209             :     if (m##self) \
     210             :         return NS_OK; \
     211             :     ENSURE_DEPS(__VA_ARGS__); \
     212             : }
     213             : 
     214        1047 : class MOZ_STACK_CLASS ComponentLoaderInfo {
     215             :   public:
     216        1046 :     explicit ComponentLoaderInfo(const nsACString& aLocation) : mLocation(aLocation) {}
     217             : 
     218             :     nsIIOService* IOService() { MOZ_ASSERT(mIOService); return mIOService; }
     219        2044 :     nsresult EnsureIOService() {
     220        2044 :         if (mIOService)
     221         998 :             return NS_OK;
     222             :         nsresult rv;
     223        1046 :         mIOService = do_GetIOService(&rv);
     224        1046 :         return rv;
     225             :     }
     226             : 
     227         765 :     nsIURI*  URI() { MOZ_ASSERT(mURI); return mURI; }
     228        2503 :     nsresult EnsureURI() {
     229        2503 :         BEGIN_ENSURE(URI, IOService);
     230        1046 :         return mIOService->NewURI(mLocation, nullptr, nullptr, getter_AddRefs(mURI));
     231             :     }
     232             : 
     233           0 :     nsIChannel* ScriptChannel() { MOZ_ASSERT(mScriptChannel); return mScriptChannel; }
     234         998 :     nsresult EnsureScriptChannel() {
     235         998 :         BEGIN_ENSURE(ScriptChannel, IOService, URI);
     236        1996 :         return NS_NewChannel(getter_AddRefs(mScriptChannel),
     237             :                              mURI,
     238             :                              nsContentUtils::GetSystemPrincipal(),
     239             :                              nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     240             :                              nsIContentPolicy::TYPE_SCRIPT,
     241             :                              nullptr, // aLoadGroup
     242             :                              nullptr, // aCallbacks
     243             :                              nsIRequest::LOAD_NORMAL,
     244         998 :                              mIOService);
     245             :     }
     246             : 
     247        1996 :     nsIURI* ResolvedURI() { MOZ_ASSERT(mResolvedURI); return mResolvedURI; }
     248        1996 :     nsresult EnsureResolvedURI() {
     249        1996 :         BEGIN_ENSURE(ResolvedURI, ScriptChannel);
     250         998 :         return mScriptChannel->GetURI(getter_AddRefs(mResolvedURI));
     251             :     }
     252             : 
     253        1828 :     nsAutoCString& Key() { return *mKey; }
     254         998 :     nsresult EnsureKey() {
     255         998 :         ENSURE_DEPS(ResolvedURI);
     256         998 :         mKey.emplace();
     257         998 :         return mResolvedURI->GetSpec(*mKey);
     258             :     }
     259             : 
     260         995 :     MOZ_MUST_USE nsresult GetLocation(nsCString& aLocation) {
     261         995 :         nsresult rv = EnsureURI();
     262         995 :         NS_ENSURE_SUCCESS(rv, rv);
     263         995 :         return mURI->GetSpec(aLocation);
     264             :     }
     265             : 
     266             :   private:
     267             :     const nsACString& mLocation;
     268             :     nsCOMPtr<nsIIOService> mIOService;
     269             :     nsCOMPtr<nsIURI> mURI;
     270             :     nsCOMPtr<nsIChannel> mScriptChannel;
     271             :     nsCOMPtr<nsIURI> mResolvedURI;
     272             :     Maybe<nsAutoCString> mKey; // This is safe because we're MOZ_STACK_CLASS
     273             : };
     274             : 
     275             : #undef BEGIN_ENSURE
     276             : #undef ENSURE_DEPS
     277             : #undef ENSURE_DEP
     278             : 
     279           0 : mozJSComponentLoader::~mozJSComponentLoader()
     280             : {
     281           0 :     if (mInitialized) {
     282           0 :         NS_ERROR("'xpcom-shutdown-loaders' was not fired before cleaning up mozJSComponentLoader");
     283           0 :         UnloadModules();
     284             :     }
     285             : 
     286           0 :     sSelf = nullptr;
     287           0 : }
     288             : 
     289             : mozJSComponentLoader*
     290             : mozJSComponentLoader::sSelf;
     291             : 
     292        3390 : NS_IMPL_ISUPPORTS(mozJSComponentLoader,
     293             :                   mozilla::ModuleLoader,
     294             :                   xpcIJSModuleLoader,
     295             :                   nsIObserver)
     296             : 
     297             : nsresult
     298           3 : mozJSComponentLoader::ReallyInit()
     299             : {
     300             :     nsresult rv;
     301             :     nsCOMPtr<nsIObserverService> obsSvc =
     302           6 :         do_GetService(kObserverServiceContractID, &rv);
     303           3 :     NS_ENSURE_SUCCESS(rv, rv);
     304             : 
     305           3 :     rv = obsSvc->AddObserver(this, "xpcom-shutdown-loaders", false);
     306           3 :     NS_ENSURE_SUCCESS(rv, rv);
     307             : 
     308           3 :     mInitialized = true;
     309             : 
     310           3 :     return NS_OK;
     311             : }
     312             : 
     313             : // For terrible compatibility reasons, we need to consider both the global
     314             : // lexical environment and the global of modules when searching for exported
     315             : // symbols.
     316             : static JSObject*
     317        1047 : ResolveModuleObjectProperty(JSContext* aCx, HandleObject aModObj, const char* name)
     318             : {
     319        1047 :     if (JS_HasExtensibleLexicalEnvironment(aModObj)) {
     320        2094 :         RootedObject lexical(aCx, JS_ExtensibleLexicalEnvironment(aModObj));
     321             :         bool found;
     322        1047 :         if (!JS_HasOwnProperty(aCx, lexical, name, &found)) {
     323           0 :             return nullptr;
     324             :         }
     325        1047 :         if (found) {
     326           0 :             return lexical;
     327             :         }
     328             :     }
     329        1047 :     return aModObj;
     330             : }
     331             : 
     332             : const mozilla::Module*
     333          48 : mozJSComponentLoader::LoadModule(FileLocation& aFile)
     334             : {
     335          48 :     if (!NS_IsMainThread()) {
     336           0 :         MOZ_ASSERT(false, "Don't use JS components off the main thread");
     337             :         return nullptr;
     338             :     }
     339             : 
     340          97 :     nsCOMPtr<nsIFile> file = aFile.GetBaseFile();
     341             : 
     342          97 :     nsCString spec;
     343          48 :     aFile.GetURIString(spec);
     344          97 :     ComponentLoaderInfo info(spec);
     345          48 :     nsresult rv = info.EnsureURI();
     346          48 :     NS_ENSURE_SUCCESS(rv, nullptr);
     347             : 
     348          48 :     if (!mInitialized) {
     349           3 :         rv = ReallyInit();
     350           3 :         if (NS_FAILED(rv))
     351           0 :             return nullptr;
     352             :     }
     353             : 
     354          97 :     AUTO_PROFILER_LABEL_DYNAMIC("mozJSComponentLoader::LoadModule", OTHER,
     355             :                                 spec.get());
     356             : 
     357             :     ModuleEntry* mod;
     358          48 :     if (mModules.Get(spec, &mod))
     359           0 :         return mod;
     360             : 
     361          97 :     dom::AutoJSAPI jsapi;
     362          48 :     jsapi.Init();
     363          48 :     JSContext* cx = jsapi.cx();
     364             : 
     365         145 :     nsAutoPtr<ModuleEntry> entry(new ModuleEntry(RootingContext::get(cx)));
     366          97 :     RootedValue dummy(cx);
     367         145 :     rv = ObjectForLocation(info, file, &entry->obj, &entry->thisObjectKey,
     368          96 :                            &entry->location, false, &dummy);
     369          49 :     if (NS_FAILED(rv)) {
     370           0 :         return nullptr;
     371             :     }
     372             : 
     373          98 :     nsCOMPtr<nsIComponentManager> cm;
     374          49 :     rv = NS_GetComponentManager(getter_AddRefs(cm));
     375          49 :     if (NS_FAILED(rv))
     376           0 :         return nullptr;
     377             : 
     378          98 :     JSAutoCompartment ac(cx, entry->obj);
     379          98 :     RootedObject entryObj(cx, entry->obj);
     380             : 
     381          98 :     RootedObject NSGetFactoryHolder(cx, ResolveModuleObjectProperty(cx, entryObj, "NSGetFactory"));
     382          98 :     RootedValue NSGetFactory_val(cx);
     383         294 :     if (!NSGetFactoryHolder ||
     384         343 :         !JS_GetProperty(cx, NSGetFactoryHolder, "NSGetFactory", &NSGetFactory_val) ||
     385          49 :         NSGetFactory_val.isUndefined())
     386             :     {
     387           0 :         return nullptr;
     388             :     }
     389             : 
     390          49 :     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
     391             :         /*
     392             :          * spec's encoding is ASCII unless it's zip file, otherwise it's
     393             :          * random encoding.  Latin1 variant is safe for random encoding.
     394             :          */
     395           0 :         JS_ReportErrorLatin1(cx, "%s has NSGetFactory property that is not a function",
     396           0 :                              spec.get());
     397           0 :         return nullptr;
     398             :     }
     399             : 
     400          98 :     RootedObject jsGetFactoryObj(cx);
     401          98 :     if (!JS_ValueToObject(cx, NSGetFactory_val, &jsGetFactoryObj) ||
     402          49 :         !jsGetFactoryObj) {
     403             :         /* XXX report error properly */
     404           0 :         return nullptr;
     405             :     }
     406             : 
     407          98 :     rv = nsXPConnect::XPConnect()->WrapJS(cx, jsGetFactoryObj,
     408             :                                           NS_GET_IID(xpcIJSGetFactory),
     409         147 :                                           getter_AddRefs(entry->getfactoryobj));
     410          49 :     if (NS_FAILED(rv)) {
     411             :         /* XXX report error properly */
     412             : #ifdef DEBUG
     413           0 :         fprintf(stderr, "mJCL: couldn't get nsIModule from jsval\n");
     414             : #endif
     415           0 :         return nullptr;
     416             :     }
     417             : 
     418             :     // Cache this module for later
     419          49 :     mModules.Put(spec, entry);
     420             : 
     421             :     // The hash owns the ModuleEntry now, forget about it
     422          49 :     return entry.forget();
     423             : }
     424             : 
     425             : void
     426         599 : mozJSComponentLoader::FindTargetObject(JSContext* aCx,
     427             :                                        MutableHandleObject aTargetObject)
     428             : {
     429         599 :     aTargetObject.set(CurrentGlobalOrNull(aCx));
     430         599 : }
     431             : 
     432             : // This requires that the keys be strings and the values be pointers.
     433             : template <class Key, class Data, class UserData>
     434             : static size_t
     435           0 : SizeOfTableExcludingThis(const nsBaseHashtable<Key, Data, UserData>& aTable,
     436             :                          MallocSizeOf aMallocSizeOf)
     437             : {
     438           0 :     size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
     439           0 :     for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
     440           0 :         n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
     441           0 :         n += iter.Data()->SizeOfIncludingThis(aMallocSizeOf);
     442             :     }
     443           0 :     return n;
     444             : }
     445             : 
     446             : size_t
     447           0 : mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
     448             : {
     449           0 :     size_t n = aMallocSizeOf(this);
     450           0 :     n += SizeOfTableExcludingThis(mModules, aMallocSizeOf);
     451           0 :     n += SizeOfTableExcludingThis(mImports, aMallocSizeOf);
     452           0 :     n += SizeOfTableExcludingThis(mInProgressImports, aMallocSizeOf);
     453           0 :     return n;
     454             : }
     455             : 
     456             : void
     457         255 : mozJSComponentLoader::CreateLoaderGlobal(JSContext* aCx,
     458             :                                          nsACString& aLocation,
     459             :                                          JSAddonId* aAddonID,
     460             :                                          MutableHandleObject aGlobal)
     461             : {
     462         510 :     RefPtr<BackstagePass> backstagePass;
     463         255 :     nsresult rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
     464         255 :     NS_ENSURE_SUCCESS_VOID(rv);
     465             : 
     466         255 :     CompartmentOptions options;
     467             : 
     468         255 :     options.creationOptions()
     469         255 :            .setSystemZone()
     470         255 :            .setAddonId(aAddonID);
     471             : 
     472         255 :     options.behaviors().setVersion(JSVERSION_LATEST);
     473             : 
     474         255 :     if (xpc::SharedMemoryEnabled())
     475         255 :         options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
     476             : 
     477             :     // Defer firing OnNewGlobalObject until after the __URI__ property has
     478             :     // been defined so the JS debugger can tell what module the global is
     479             :     // for
     480         510 :     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     481             :     rv = nsXPConnect::XPConnect()->
     482         510 :         InitClassesWithNewWrappedGlobal(aCx,
     483         255 :                                         static_cast<nsIGlobalObject*>(backstagePass),
     484             :                                         nsContentUtils::GetSystemPrincipal(),
     485             :                                         nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK,
     486             :                                         options,
     487         510 :                                         getter_AddRefs(holder));
     488         255 :     NS_ENSURE_SUCCESS_VOID(rv);
     489             : 
     490         510 :     RootedObject global(aCx, holder->GetJSObject());
     491         255 :     NS_ENSURE_TRUE_VOID(global);
     492             : 
     493         255 :     backstagePass->SetGlobalObject(global);
     494             : 
     495         510 :     JSAutoCompartment ac(aCx, global);
     496        1020 :     if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
     497         765 :         !JS_DefineProfilingFunctions(aCx, global)) {
     498           0 :         return;
     499             :     }
     500             : 
     501             :     // Set the location information for the new global, so that tools like
     502             :     // about:memory may use that information
     503         255 :     xpc::SetLocationForGlobal(global, aLocation);
     504             : 
     505         255 :     aGlobal.set(global);
     506             : }
     507             : 
     508             : JSObject*
     509         255 : mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx,
     510             :                                                nsIFile* aComponentFile,
     511             :                                                nsIURI* aURI,
     512             :                                                bool* aRealFile)
     513             : {
     514         510 :     nsAutoCString nativePath;
     515         255 :     NS_ENSURE_SUCCESS(aURI->GetSpec(nativePath), nullptr);
     516             : 
     517         510 :     RootedObject globalObj(aCx);
     518             : 
     519         255 :     CreateLoaderGlobal(aCx, nativePath, MapURIToAddonID(aURI), &globalObj);
     520             : 
     521             :     // |thisObj| is the object we set properties on for a particular .jsm.
     522             :     // XXX Right now, thisObj is always globalObj, but if we start
     523             :     // sharing globals between jsms, they won't be the same.
     524             :     // See bug 1186409.
     525         510 :     RootedObject thisObj(aCx, globalObj);
     526         255 :     NS_ENSURE_TRUE(thisObj, nullptr);
     527             : 
     528         510 :     JSAutoCompartment ac(aCx, thisObj);
     529             : 
     530         255 :     *aRealFile = false;
     531             : 
     532             :     // need to be extra careful checking for URIs pointing to files
     533             :     // EnsureFile may not always get called, especially on resource URIs
     534             :     // so we need to call GetFile to make sure this is a valid file
     535         255 :     nsresult rv = NS_OK;
     536         510 :     nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
     537         510 :     nsCOMPtr<nsIFile> testFile;
     538         255 :     if (NS_SUCCEEDED(rv)) {
     539         248 :         fileURL->GetFile(getter_AddRefs(testFile));
     540             :     }
     541             : 
     542         255 :     if (testFile) {
     543         248 :         *aRealFile = true;
     544             : 
     545         248 :         if (XRE_IsParentProcess()) {
     546         362 :             RootedObject locationObj(aCx);
     547             : 
     548         362 :             rv = nsXPConnect::XPConnect()->WrapNative(aCx, thisObj, aComponentFile,
     549             :                                                       NS_GET_IID(nsIFile),
     550         181 :                                                       locationObj.address());
     551         181 :             NS_ENSURE_SUCCESS(rv, nullptr);
     552         181 :             NS_ENSURE_TRUE(locationObj, nullptr);
     553             : 
     554         181 :             if (!JS_DefineProperty(aCx, thisObj, "__LOCATION__", locationObj, 0))
     555           0 :                 return nullptr;
     556             :         }
     557             :     }
     558             : 
     559             :     // Expose the URI from which the script was imported through a special
     560             :     // variable that we insert into the JSM.
     561         510 :     RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
     562         255 :     NS_ENSURE_TRUE(exposedUri, nullptr);
     563             : 
     564         255 :     if (!JS_DefineProperty(aCx, thisObj, "__URI__", exposedUri, 0))
     565           0 :         return nullptr;
     566             : 
     567             :     {
     568             :         // AutoEntryScript required to invoke debugger hook, which is a
     569             :         // Gecko-specific concept at present.
     570             :         dom::AutoEntryScript aes(globalObj,
     571         510 :                                  "component loader report global");
     572         255 :         JS_FireOnNewGlobalObject(aes.cx(), globalObj);
     573             :     }
     574             : 
     575         255 :     return thisObj;
     576             : }
     577             : 
     578             : nsresult
     579         255 : mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
     580             :                                         nsIFile* aComponentFile,
     581             :                                         MutableHandleObject aObject,
     582             :                                         MutableHandleScript aTableScript,
     583             :                                         char** aLocation,
     584             :                                         bool aPropagateExceptions,
     585             :                                         MutableHandleValue aException)
     586             : {
     587         255 :     MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
     588             : 
     589         511 :     dom::AutoJSAPI jsapi;
     590         255 :     jsapi.Init();
     591         255 :     JSContext* cx = jsapi.cx();
     592             : 
     593         255 :     bool realFile = false;
     594         255 :     nsresult rv = aInfo.EnsureURI();
     595         255 :     NS_ENSURE_SUCCESS(rv, rv);
     596         510 :     RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aInfo.URI(),
     597         511 :                                                   &realFile));
     598         255 :     NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
     599         255 :     MOZ_ASSERT(JS_IsGlobalObject(obj));
     600             : 
     601         511 :     JSAutoCompartment ac(cx, obj);
     602             : 
     603         511 :     RootedScript script(cx);
     604             : 
     605         511 :     nsAutoCString nativePath;
     606         255 :     rv = aInfo.URI()->GetSpec(nativePath);
     607         255 :     NS_ENSURE_SUCCESS(rv, rv);
     608             : 
     609             :     // Before compiling the script, first check to see if we have it in
     610             :     // the startupcache.  Note: as a rule, startupcache errors are not fatal
     611             :     // to loading the script, since we can always slow-load.
     612             : 
     613         255 :     bool writeToCache = false;
     614         255 :     StartupCache* cache = StartupCache::GetSingleton();
     615             : 
     616         511 :     nsAutoCString cachePath(kJSCachePrefix);
     617         255 :     rv = PathifyURI(aInfo.URI(), cachePath);
     618         255 :     NS_ENSURE_SUCCESS(rv, rv);
     619             : 
     620         255 :     script = ScriptPreloader::GetSingleton().GetCachedScript(cx, cachePath);
     621         255 :     if (!script && cache) {
     622          77 :         ReadCachedScript(cache, cachePath, cx, &script);
     623             :     }
     624             : 
     625         255 :     if (script) {
     626         154 :         LOG(("Successfully loaded %s from startupcache\n", nativePath.get()));
     627         101 :     } else if (cache) {
     628             :         // This is ok, it just means the script is not yet in the
     629             :         // cache. Could mean that the cache was corrupted and got removed,
     630             :         // but either way we're going to write this out.
     631          51 :         writeToCache = true;
     632             :         // ReadCachedScript may have set a pending exception.
     633          51 :         JS_ClearPendingException(cx);
     634             :     }
     635             : 
     636         255 :     if (!script) {
     637             :         // The script wasn't in the cache , so compile it now.
     638         101 :         LOG(("Slow loading %s\n", nativePath.get()));
     639             : 
     640             :         // Use lazy source if we're using the startup cache. Non-lazy source +
     641             :         // startup cache regresses installer size (due to source code stored in
     642             :         // XDR encoded modules in omni.ja). Also, XDR decoding is relatively
     643             :         // fast. When we're not using the startup cache, we want to use non-lazy
     644             :         // source code so that we can use lazy parsing.
     645             :         // See bug 1303754.
     646         202 :         CompileOptions options(cx);
     647         101 :         options.setNoScriptRval(true)
     648         101 :                .setVersion(JSVERSION_LATEST)
     649         202 :                .setFileAndLine(nativePath.get(), 1)
     650         202 :                .setSourceIsLazy(!!cache);
     651             : 
     652         101 :         if (realFile) {
     653         202 :             AutoMemMap map;
     654         101 :             MOZ_TRY(map.init(aComponentFile));
     655             : 
     656             :             // Note: exceptions will get handled further down;
     657             :             // don't early return for them here.
     658         101 :             auto buf = map.get<char>();
     659         101 :             Compile(cx, options, buf.get(), map.size(), &script);
     660             :         } else {
     661           0 :             rv = aInfo.EnsureScriptChannel();
     662           0 :             NS_ENSURE_SUCCESS(rv, rv);
     663           0 :             nsCOMPtr<nsIInputStream> scriptStream;
     664           0 :             rv = NS_MaybeOpenChannelUsingOpen2(aInfo.ScriptChannel(),
     665           0 :                    getter_AddRefs(scriptStream));
     666           0 :             NS_ENSURE_SUCCESS(rv, rv);
     667             : 
     668             :             uint64_t len64;
     669             :             uint32_t bytesRead;
     670             : 
     671           0 :             rv = scriptStream->Available(&len64);
     672           0 :             NS_ENSURE_SUCCESS(rv, rv);
     673           0 :             NS_ENSURE_TRUE(len64 < UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
     674           0 :             if (!len64)
     675           0 :                 return NS_ERROR_FAILURE;
     676           0 :             uint32_t len = (uint32_t)len64;
     677             : 
     678             :             /* malloc an internal buf the size of the file */
     679           0 :             auto buf = MakeUniqueFallible<char[]>(len + 1);
     680           0 :             if (!buf)
     681           0 :                 return NS_ERROR_OUT_OF_MEMORY;
     682             : 
     683             :             /* read the file in one swoop */
     684           0 :             rv = scriptStream->Read(buf.get(), len, &bytesRead);
     685           0 :             if (bytesRead != len)
     686           0 :                 return NS_BASE_STREAM_OSERROR;
     687             : 
     688           0 :             buf[len] = '\0';
     689             : 
     690           0 :             Compile(cx, options, buf.get(), bytesRead, &script);
     691             :         }
     692             :         // Propagate the exception, if one exists. Also, don't leave the stale
     693             :         // exception on this context.
     694         101 :         if (!script && aPropagateExceptions && jsapi.HasException()) {
     695           0 :             if (!jsapi.StealException(aException))
     696           0 :                 return NS_ERROR_OUT_OF_MEMORY;
     697             :         }
     698             :     }
     699             : 
     700         255 :     if (!script) {
     701           0 :         return NS_ERROR_FAILURE;
     702             :     }
     703             : 
     704         255 :     ScriptPreloader::GetSingleton().NoteScript(nativePath, cachePath, script);
     705             : 
     706         255 :     if (writeToCache) {
     707             :         // We successfully compiled the script, so cache it.
     708          51 :         rv = WriteCachedScript(cache, cachePath, cx, script);
     709             : 
     710             :         // Don't treat failure to write as fatal, since we might be working
     711             :         // with a read-only cache.
     712          51 :         if (NS_SUCCEEDED(rv)) {
     713          51 :             LOG(("Successfully wrote to cache\n"));
     714             :         } else {
     715           0 :             LOG(("Failed to write to cache\n"));
     716             :         }
     717             :     }
     718             : 
     719             :     // Assign aObject here so that it's available to recursive imports.
     720             :     // See bug 384168.
     721         255 :     aObject.set(obj);
     722             : 
     723         255 :     aTableScript.set(script);
     724             : 
     725             : 
     726             :     {   // Scope for AutoEntryScript
     727             : 
     728             :         // We're going to run script via JS_ExecuteScript, so we need an
     729             :         // AutoEntryScript. This is Gecko-specific and not in any spec.
     730             :         dom::AutoEntryScript aes(CurrentGlobalOrNull(cx),
     731         511 :                                  "component loader load module");
     732         255 :         JSContext* aescx = aes.cx();
     733         511 :         JS::RootedValue rval(cx);
     734         255 :         if (!JS::CloneAndExecuteScript(aescx, script, &rval)) {
     735           0 :             if (aPropagateExceptions && aes.HasException()) {
     736             :                 // Ignore return value because we're returning an error code
     737             :                 // anyway.
     738           0 :                 Unused << aes.StealException(aException);
     739             :             }
     740           0 :             aObject.set(nullptr);
     741           0 :             aTableScript.set(nullptr);
     742           0 :             return NS_ERROR_FAILURE;
     743             :         }
     744             :     }
     745             : 
     746             :     /* Freed when we remove from the table. */
     747         256 :     *aLocation = ToNewCString(nativePath);
     748         256 :     if (!*aLocation) {
     749           0 :         aObject.set(nullptr);
     750           0 :         aTableScript.set(nullptr);
     751           0 :         return NS_ERROR_OUT_OF_MEMORY;
     752             :     }
     753             : 
     754         256 :     return NS_OK;
     755             : }
     756             : 
     757             : void
     758           0 : mozJSComponentLoader::UnloadModules()
     759             : {
     760           0 :     mInitialized = false;
     761             : 
     762           0 :     mInProgressImports.Clear();
     763           0 :     mImports.Clear();
     764             : 
     765           0 :     for (auto iter = mModules.Iter(); !iter.Done(); iter.Next()) {
     766           0 :         iter.Data()->Clear();
     767           0 :         iter.Remove();
     768             :     }
     769           0 : }
     770             : 
     771             : NS_IMETHODIMP
     772         998 : mozJSComponentLoader::Import(const nsACString& registryLocation,
     773             :                              HandleValue targetValArg,
     774             :                              JSContext* cx,
     775             :                              uint8_t optionalArgc,
     776             :                              MutableHandleValue retval)
     777             : {
     778         998 :     MOZ_ASSERT(nsContentUtils::IsCallerChrome());
     779             : 
     780        1996 :     RootedValue targetVal(cx, targetValArg);
     781        1996 :     RootedObject targetObject(cx, nullptr);
     782         998 :     if (optionalArgc) {
     783             :         // The caller passed in the optional second argument. Get it.
     784         401 :         if (targetVal.isObject()) {
     785             :             // If we're passing in something like a content DOM window, chances
     786             :             // are the caller expects the properties to end up on the object
     787             :             // proper and not on the Xray holder. This is dubious, but can be used
     788             :             // during testing. Given that dumb callers can already leak JSMs into
     789             :             // content by passing a raw content JS object (where Xrays aren't
     790             :             // possible), we aim for consistency here. Waive xray.
     791        1203 :             if (WrapperFactory::IsXrayWrapper(&targetVal.toObject()) &&
     792         401 :                 !WrapperFactory::WaiveXrayAndWrap(cx, &targetVal))
     793             :             {
     794           0 :                 return NS_ERROR_FAILURE;
     795             :             }
     796         401 :             targetObject = &targetVal.toObject();
     797           0 :         } else if (!targetVal.isNull()) {
     798             :             // If targetVal isNull(), we actually want to leave targetObject null.
     799             :             // Not doing so breaks |make package|.
     800           0 :             return ReportOnCallerUTF8(cx, ERROR_SCOPE_OBJ,
     801           0 :                                       PromiseFlatCString(registryLocation).get());
     802             :         }
     803             :     } else {
     804         597 :         FindTargetObject(cx, &targetObject);
     805             :     }
     806             : 
     807        1996 :     Maybe<JSAutoCompartment> ac;
     808         998 :     if (targetObject) {
     809         998 :         ac.emplace(cx, targetObject);
     810             :     }
     811             : 
     812        1996 :     RootedObject global(cx);
     813         998 :     nsresult rv = ImportInto(registryLocation, targetObject, cx, &global);
     814             : 
     815         998 :     if (global) {
     816         998 :         if (!JS_WrapObject(cx, &global)) {
     817           0 :             NS_ERROR("can't wrap return value");
     818           0 :             return NS_ERROR_FAILURE;
     819             :         }
     820             : 
     821         998 :         retval.setObject(*global);
     822             :     }
     823         998 :     return rv;
     824             : }
     825             : 
     826             : NS_IMETHODIMP
     827           0 : mozJSComponentLoader::ImportInto(const nsACString& aLocation,
     828             :                                  JSObject* aTargetObj,
     829             :                                  nsAXPCNativeCallContext* cc,
     830             :                                  JSObject** _retval)
     831             : {
     832             :     JSContext* callercx;
     833           0 :     nsresult rv = cc->GetJSContext(&callercx);
     834           0 :     NS_ENSURE_SUCCESS(rv, rv);
     835             : 
     836           0 :     RootedObject targetObject(callercx, aTargetObj);
     837           0 :     RootedObject global(callercx);
     838           0 :     rv = ImportInto(aLocation, targetObject, callercx, &global);
     839           0 :     NS_ENSURE_SUCCESS(rv, rv);
     840           0 :     *_retval = global;
     841           0 :     return NS_OK;
     842             : }
     843             : 
     844             : NS_IMETHODIMP
     845           0 : mozJSComponentLoader::IsModuleLoaded(const nsACString& aLocation,
     846             :                                      bool* retval)
     847             : {
     848           0 :     MOZ_ASSERT(nsContentUtils::IsCallerChrome());
     849             : 
     850             :     nsresult rv;
     851           0 :     if (!mInitialized) {
     852           0 :         rv = ReallyInit();
     853           0 :         NS_ENSURE_SUCCESS(rv, rv);
     854             :     }
     855             : 
     856           0 :     ComponentLoaderInfo info(aLocation);
     857           0 :     rv = info.EnsureKey();
     858           0 :     NS_ENSURE_SUCCESS(rv, rv);
     859             : 
     860           0 :     *retval = !!mImports.Get(info.Key());
     861           0 :     return NS_OK;
     862             : }
     863             : 
     864           3 : NS_IMETHODIMP mozJSComponentLoader::LoadedModules(uint32_t* length,
     865             :                                                   char*** aModules)
     866             : {
     867           6 :     char** modules = new char*[mImports.Count()];
     868           3 :     *length = mImports.Count();
     869           3 :     *aModules = modules;
     870             : 
     871         185 :     for (auto iter = mImports.Iter(); !iter.Done(); iter.Next()) {
     872         182 :         *modules = NS_strdup(iter.Data()->location);
     873         182 :         modules++;
     874             :     }
     875             : 
     876           3 :     return NS_OK;
     877             : }
     878             : 
     879           3 : NS_IMETHODIMP mozJSComponentLoader::LoadedComponents(uint32_t* length,
     880             :                                                      char*** aComponents)
     881             : {
     882           6 :     char** comp = new char*[mModules.Count()];
     883           3 :     *length = mModules.Count();
     884           3 :     *aComponents = comp;
     885             : 
     886          61 :     for (auto iter = mModules.Iter(); !iter.Done(); iter.Next()) {
     887          58 :         *comp = NS_strdup(iter.Data()->location);
     888          58 :         comp++;
     889             :     }
     890             : 
     891           3 :     return NS_OK;
     892             : }
     893             : 
     894             : static JSObject*
     895        1619 : ResolveModuleObjectPropertyById(JSContext* aCx, HandleObject aModObj, HandleId id)
     896             : {
     897        1619 :     if (JS_HasExtensibleLexicalEnvironment(aModObj)) {
     898        3223 :         RootedObject lexical(aCx, JS_ExtensibleLexicalEnvironment(aModObj));
     899             :         bool found;
     900        1619 :         if (!JS_HasOwnPropertyById(aCx, lexical, id, &found)) {
     901           0 :             return nullptr;
     902             :         }
     903        1619 :         if (found) {
     904          15 :             return lexical;
     905             :         }
     906             :     }
     907        1604 :     return aModObj;
     908             : }
     909             : 
     910             : nsresult
     911         998 : mozJSComponentLoader::ImportInto(const nsACString& aLocation,
     912             :                                  HandleObject targetObj,
     913             :                                  JSContext* callercx,
     914             :                                  MutableHandleObject vp)
     915             : {
     916         998 :     vp.set(nullptr);
     917             : 
     918             :     nsresult rv;
     919         998 :     if (!mInitialized) {
     920           0 :         rv = ReallyInit();
     921           0 :         NS_ENSURE_SUCCESS(rv, rv);
     922             :     }
     923             : 
     924        1996 :     ComponentLoaderInfo info(aLocation);
     925         998 :     rv = info.EnsureResolvedURI();
     926         998 :     NS_ENSURE_SUCCESS(rv, rv);
     927             : 
     928             :     // get the JAR if there is one
     929        1996 :     nsCOMPtr<nsIJARURI> jarURI;
     930         998 :     jarURI = do_QueryInterface(info.ResolvedURI(), &rv);
     931        1996 :     nsCOMPtr<nsIFileURL> baseFileURL;
     932         998 :     if (NS_SUCCEEDED(rv)) {
     933           0 :         nsCOMPtr<nsIURI> baseURI;
     934           0 :         while (jarURI) {
     935           0 :             jarURI->GetJARFile(getter_AddRefs(baseURI));
     936           0 :             jarURI = do_QueryInterface(baseURI, &rv);
     937             :         }
     938           0 :         baseFileURL = do_QueryInterface(baseURI, &rv);
     939           0 :         NS_ENSURE_SUCCESS(rv, rv);
     940             :     } else {
     941         998 :         baseFileURL = do_QueryInterface(info.ResolvedURI(), &rv);
     942         998 :         NS_ENSURE_SUCCESS(rv, rv);
     943             :     }
     944             : 
     945        1996 :     nsCOMPtr<nsIFile> sourceFile;
     946         998 :     rv = baseFileURL->GetFile(getter_AddRefs(sourceFile));
     947         998 :     NS_ENSURE_SUCCESS(rv, rv);
     948             : 
     949        1996 :     nsCOMPtr<nsIFile> sourceLocalFile;
     950         998 :     sourceLocalFile = do_QueryInterface(sourceFile, &rv);
     951         998 :     NS_ENSURE_SUCCESS(rv, rv);
     952             : 
     953         998 :     rv = info.EnsureKey();
     954         998 :     NS_ENSURE_SUCCESS(rv, rv);
     955             : 
     956             :     ModuleEntry* mod;
     957        1996 :     nsAutoPtr<ModuleEntry> newEntry;
     958         998 :     if (!mImports.Get(info.Key(), &mod) && !mInProgressImports.Get(info.Key(), &mod)) {
     959         414 :         newEntry = new ModuleEntry(RootingContext::get(callercx));
     960         207 :         if (!newEntry)
     961           0 :             return NS_ERROR_OUT_OF_MEMORY;
     962         207 :         mInProgressImports.Put(info.Key(), newEntry);
     963             : 
     964         207 :         rv = info.EnsureURI();
     965         207 :         NS_ENSURE_SUCCESS(rv, rv);
     966         414 :         RootedValue exception(callercx);
     967         621 :         rv = ObjectForLocation(info, sourceLocalFile, &newEntry->obj,
     968         207 :                                &newEntry->thisObjectKey,
     969         207 :                                &newEntry->location, true, &exception);
     970             : 
     971         207 :         mInProgressImports.Remove(info.Key());
     972             : 
     973         207 :         if (NS_FAILED(rv)) {
     974           0 :             if (!exception.isUndefined()) {
     975             :                 // An exception was thrown during compilation. Propagate it
     976             :                 // out to our caller so they can report it.
     977           0 :                 if (!JS_WrapValue(callercx, &exception))
     978           0 :                     return NS_ERROR_OUT_OF_MEMORY;
     979           0 :                 JS_SetPendingException(callercx, exception);
     980           0 :                 return NS_OK;
     981             :             }
     982             : 
     983             :             // Something failed, but we don't know what it is, guess.
     984           0 :             return NS_ERROR_FILE_NOT_FOUND;
     985             :         }
     986             : 
     987         207 :         mod = newEntry;
     988             :     }
     989             : 
     990         998 :     MOZ_ASSERT(mod->obj, "Import table contains entry with no object");
     991         998 :     vp.set(mod->obj);
     992             : 
     993         998 :     if (targetObj) {
     994             :         // cxhelper must be created before jsapi, so that jsapi is destroyed and
     995             :         // pops any context it has pushed before we report to the caller context.
     996        1996 :         JSCLContextHelper cxhelper(callercx);
     997             : 
     998             :         // Even though we are calling JS_SetPropertyById on targetObj, we want
     999             :         // to ensure that we never run script here, so we use an AutoJSAPI and
    1000             :         // not an AutoEntryScript.
    1001        1996 :         dom::AutoJSAPI jsapi;
    1002         998 :         jsapi.Init();
    1003         998 :         JSContext* cx = jsapi.cx();
    1004        1996 :         JSAutoCompartment ac(cx, mod->obj);
    1005             : 
    1006        1996 :         RootedValue symbols(cx);
    1007        1996 :         RootedObject exportedSymbolsHolder(cx, ResolveModuleObjectProperty(cx, mod->obj,
    1008        1996 :                                                                            "EXPORTED_SYMBOLS"));
    1009        4990 :         if (!exportedSymbolsHolder ||
    1010        4990 :             !JS_GetProperty(cx, exportedSymbolsHolder,
    1011             :                             "EXPORTED_SYMBOLS", &symbols)) {
    1012           0 :             nsCString location;
    1013           0 :             rv = info.GetLocation(location);
    1014           0 :             NS_ENSURE_SUCCESS(rv, rv);
    1015           0 :             return ReportOnCallerUTF8(cxhelper, ERROR_NOT_PRESENT,
    1016           0 :                                       location.get());
    1017             :         }
    1018             : 
    1019             :         bool isArray;
    1020         998 :         if (!JS_IsArrayObject(cx, symbols, &isArray)) {
    1021           0 :             return NS_ERROR_FAILURE;
    1022             :         }
    1023         998 :         if (!isArray) {
    1024           0 :             nsCString location;
    1025           0 :             rv = info.GetLocation(location);
    1026           0 :             NS_ENSURE_SUCCESS(rv, rv);
    1027           0 :             return ReportOnCallerUTF8(cxhelper, ERROR_NOT_AN_ARRAY,
    1028           0 :                                       location.get());
    1029             :         }
    1030             : 
    1031        1996 :         RootedObject symbolsObj(cx, &symbols.toObject());
    1032             : 
    1033             :         // Iterate over symbols array, installing symbols on targetObj:
    1034             : 
    1035         998 :         uint32_t symbolCount = 0;
    1036         998 :         if (!JS_GetArrayLength(cx, symbolsObj, &symbolCount)) {
    1037           0 :             nsCString location;
    1038           0 :             rv = info.GetLocation(location);
    1039           0 :             NS_ENSURE_SUCCESS(rv, rv);
    1040           0 :             return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_ARRAY_LENGTH,
    1041           0 :                                       location.get());
    1042             :         }
    1043             : 
    1044             : #ifdef DEBUG
    1045        1996 :         nsAutoCString logBuffer;
    1046             : #endif
    1047             : 
    1048        1996 :         RootedValue value(cx);
    1049        1996 :         RootedId symbolId(cx);
    1050        1996 :         RootedObject symbolHolder(cx);
    1051        2617 :         for (uint32_t i = 0; i < symbolCount; ++i) {
    1052        9714 :             if (!JS_GetElement(cx, symbolsObj, i, &value) ||
    1053       11333 :                 !value.isString() ||
    1054        6476 :                 !JS_ValueToId(cx, value, &symbolId)) {
    1055           0 :                 nsCString location;
    1056           0 :                 rv = info.GetLocation(location);
    1057           0 :                 NS_ENSURE_SUCCESS(rv, rv);
    1058           0 :                 return ReportOnCallerUTF8(cxhelper, ERROR_ARRAY_ELEMENT,
    1059           0 :                                           location.get(), i);
    1060             :             }
    1061             : 
    1062        1619 :             symbolHolder = ResolveModuleObjectPropertyById(cx, mod->obj, symbolId);
    1063        9714 :             if (!symbolHolder ||
    1064        9714 :                 !JS_GetPropertyById(cx, symbolHolder, symbolId, &value)) {
    1065           0 :                 JSAutoByteString bytes;
    1066           0 :                 RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
    1067           0 :                 if (!bytes.encodeUtf8(cx, symbolStr))
    1068           0 :                     return NS_ERROR_FAILURE;
    1069           0 :                 nsCString location;
    1070           0 :                 rv = info.GetLocation(location);
    1071           0 :                 NS_ENSURE_SUCCESS(rv, rv);
    1072           0 :                 return ReportOnCallerUTF8(cxhelper, ERROR_GETTING_SYMBOL,
    1073           0 :                                           location.get(), bytes.ptr());
    1074             :             }
    1075             : 
    1076        3238 :             JSAutoCompartment target_ac(cx, targetObj);
    1077             : 
    1078        1619 :             JS_MarkCrossZoneId(cx, symbolId);
    1079             : 
    1080        8095 :             if (!JS_WrapValue(cx, &value) ||
    1081        6476 :                 !JS_SetPropertyById(cx, targetObj, symbolId, value)) {
    1082           0 :                 JSAutoByteString bytes;
    1083           0 :                 RootedString symbolStr(cx, JSID_TO_STRING(symbolId));
    1084           0 :                 if (!bytes.encodeUtf8(cx, symbolStr))
    1085           0 :                     return NS_ERROR_FAILURE;
    1086           0 :                 nsCString location;
    1087           0 :                 rv = info.GetLocation(location);
    1088           0 :                 NS_ENSURE_SUCCESS(rv, rv);
    1089           0 :                 return ReportOnCallerUTF8(cxhelper, ERROR_SETTING_SYMBOL,
    1090           0 :                                           location.get(), bytes.ptr());
    1091             :             }
    1092             : #ifdef DEBUG
    1093        1619 :             if (i == 0) {
    1094         995 :                 logBuffer.AssignLiteral("Installing symbols [ ");
    1095             :             }
    1096        3238 :             JSAutoByteString bytes(cx, JSID_TO_STRING(symbolId));
    1097        1619 :             if (!!bytes)
    1098        1619 :                 logBuffer.Append(bytes.ptr());
    1099        1619 :             logBuffer.Append(' ');
    1100        1619 :             if (i == symbolCount - 1) {
    1101        1990 :                 nsCString location;
    1102         995 :                 rv = info.GetLocation(location);
    1103         995 :                 NS_ENSURE_SUCCESS(rv, rv);
    1104         995 :                 LOG(("%s] from %s\n", logBuffer.get(), location.get()));
    1105             :             }
    1106             : #endif
    1107             :         }
    1108             :     }
    1109             : 
    1110             :     // Cache this module for later
    1111         998 :     if (newEntry) {
    1112         207 :         mImports.Put(info.Key(), newEntry);
    1113         207 :         newEntry.forget();
    1114             :     }
    1115             : 
    1116         998 :     return NS_OK;
    1117             : }
    1118             : 
    1119             : NS_IMETHODIMP
    1120           0 : mozJSComponentLoader::Unload(const nsACString & aLocation)
    1121             : {
    1122             :     nsresult rv;
    1123             : 
    1124           0 :     if (!mInitialized) {
    1125           0 :         return NS_OK;
    1126             :     }
    1127             : 
    1128           0 :     ComponentLoaderInfo info(aLocation);
    1129           0 :     rv = info.EnsureKey();
    1130           0 :     NS_ENSURE_SUCCESS(rv, rv);
    1131             :     ModuleEntry* mod;
    1132           0 :     if (mImports.Get(info.Key(), &mod)) {
    1133           0 :         mImports.Remove(info.Key());
    1134             :     }
    1135             : 
    1136           0 :     return NS_OK;
    1137             : }
    1138             : 
    1139             : NS_IMETHODIMP
    1140           0 : mozJSComponentLoader::Observe(nsISupports* subject, const char* topic,
    1141             :                               const char16_t* data)
    1142             : {
    1143           0 :     if (!strcmp(topic, "xpcom-shutdown-loaders")) {
    1144           0 :         UnloadModules();
    1145             :     } else {
    1146           0 :         NS_ERROR("Unexpected observer topic.");
    1147             :     }
    1148             : 
    1149           0 :     return NS_OK;
    1150             : }
    1151             : 
    1152             : size_t
    1153           0 : mozJSComponentLoader::ModuleEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
    1154             : {
    1155           0 :     size_t n = aMallocSizeOf(this);
    1156           0 :     n += aMallocSizeOf(location);
    1157             : 
    1158           0 :     return n;
    1159             : }
    1160             : 
    1161             : /* static */ already_AddRefed<nsIFactory>
    1162          51 : mozJSComponentLoader::ModuleEntry::GetFactory(const mozilla::Module& module,
    1163             :                                               const mozilla::Module::CIDEntry& entry)
    1164             : {
    1165          51 :     const ModuleEntry& self = static_cast<const ModuleEntry&>(module);
    1166          51 :     MOZ_ASSERT(self.getfactoryobj, "Handing out an uninitialized module?");
    1167             : 
    1168         102 :     nsCOMPtr<nsIFactory> f;
    1169          51 :     nsresult rv = self.getfactoryobj->Get(*entry.cid, getter_AddRefs(f));
    1170          51 :     if (NS_FAILED(rv))
    1171           0 :         return nullptr;
    1172             : 
    1173          51 :     return f.forget();
    1174             : }
    1175             : 
    1176             : //----------------------------------------------------------------------
    1177             : 
    1178         998 : JSCLContextHelper::JSCLContextHelper(JSContext* aCx)
    1179             :     : mContext(aCx)
    1180         998 :     , mBuf(nullptr)
    1181             : {
    1182         998 : }
    1183             : 
    1184        1996 : JSCLContextHelper::~JSCLContextHelper()
    1185             : {
    1186         998 :     if (mBuf) {
    1187           0 :         JS_ReportErrorUTF8(mContext, "%s", mBuf.get());
    1188             :     }
    1189         998 : }
    1190             : 
    1191             : void
    1192           0 : JSCLContextHelper::reportErrorAfterPop(UniqueChars&& buf)
    1193             : {
    1194           0 :     MOZ_ASSERT(!mBuf, "Already called reportErrorAfterPop");
    1195           0 :     mBuf = Move(buf);
    1196           0 : }

Generated by: LCOV version 1.13