js/xpconnect/loader/mozJSComponentLoader.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     7 #include "mozilla/Attributes.h"
     9 #ifdef MOZ_LOGGING
    10 #define FORCE_PR_LOG
    11 #endif
    13 #include <cstdarg>
    15 #include "prlog.h"
    16 #ifdef ANDROID
    17 #include <android/log.h>
    18 #endif
    19 #ifdef XP_WIN
    20 #include <windows.h>
    21 #endif
    23 #include "jsapi.h"
    24 #include "nsCOMPtr.h"
    25 #include "nsAutoPtr.h"
    26 #include "nsIComponentManager.h"
    27 #include "mozilla/Module.h"
    28 #include "nsIFile.h"
    29 #include "mozJSComponentLoader.h"
    30 #include "mozJSLoaderUtils.h"
    31 #include "nsIJSRuntimeService.h"
    32 #include "nsIXPConnect.h"
    33 #include "nsIObserverService.h"
    34 #include "nsIScriptSecurityManager.h"
    35 #include "nsIFileURL.h"
    36 #include "nsIJARURI.h"
    37 #include "nsNetUtil.h"
    38 #include "nsDOMBlobBuilder.h"
    39 #include "jsprf.h"
    40 #include "nsJSPrincipals.h"
    41 #include "xpcprivate.h"
    42 #include "xpcpublic.h"
    43 #include "nsContentUtils.h"
    44 #include "nsCxPusher.h"
    45 #include "WrapperFactory.h"
    47 #include "mozilla/scache/StartupCache.h"
    48 #include "mozilla/scache/StartupCacheUtils.h"
    49 #include "mozilla/Preferences.h"
    51 #include "js/OldDebugAPI.h"
    53 using namespace mozilla;
    54 using namespace mozilla::scache;
    55 using namespace xpc;
    56 using namespace JS;
    58 // This JSClass exists to trick silly code that expects toString()ing the
    59 // global in a component scope to return something with "BackstagePass" in it
    60 // to continue working.
    61 static const JSClass kFakeBackstagePassJSClass =
    62 {
    63     "FakeBackstagePass",
    64     0,
    65     JS_PropertyStub,
    66     JS_DeletePropertyStub,
    67     JS_PropertyStub,
    68     JS_StrictPropertyStub,
    69     JS_EnumerateStub,
    70     JS_ResolveStub,
    71     JS_ConvertStub
    72 };
    74 static const char kJSRuntimeServiceContractID[] = "@mozilla.org/js/xpc/RuntimeService;1";
    75 static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1";
    76 static const char kObserverServiceContractID[] = "@mozilla.org/observer-service;1";
    77 static const char kJSCachePrefix[] = "jsloader";
    79 #define HAVE_PR_MEMMAP
    81 /**
    82  * Buffer sizes for serialization and deserialization of scripts.
    83  * FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008
    84  */
    85 #define XPC_SERIALIZATION_BUFFER_SIZE   (64 * 1024)
    86 #define XPC_DESERIALIZATION_BUFFER_SIZE (12 * 8192)
    88 #ifdef PR_LOGGING
    89 // NSPR_LOG_MODULES=JSComponentLoader:5
    90 static PRLogModuleInfo *gJSCLLog;
    91 #endif
    93 #define LOG(args) PR_LOG(gJSCLLog, PR_LOG_DEBUG, args)
    95 // Components.utils.import error messages
    96 #define ERROR_SCOPE_OBJ "%s - Second argument must be an object."
    97 #define ERROR_NOT_PRESENT "%s - EXPORTED_SYMBOLS is not present."
    98 #define ERROR_NOT_AN_ARRAY "%s - EXPORTED_SYMBOLS is not an array."
    99 #define ERROR_GETTING_ARRAY_LENGTH "%s - Error getting array length of EXPORTED_SYMBOLS."
   100 #define ERROR_ARRAY_ELEMENT "%s - EXPORTED_SYMBOLS[%d] is not a string."
   101 #define ERROR_GETTING_SYMBOL "%s - Could not get symbol '%s'."
   102 #define ERROR_SETTING_SYMBOL "%s - Could not set symbol '%s' on target object."
   104 static bool
   105 Dump(JSContext *cx, unsigned argc, Value *vp)
   106 {
   107     CallArgs args = CallArgsFromVp(argc, vp);
   109     if (args.length() == 0)
   110         return true;
   112     JSString *str = JS::ToString(cx, args[0]);
   113     if (!str)
   114         return false;
   116     size_t length;
   117     const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
   118     if (!chars)
   119         return false;
   121     NS_ConvertUTF16toUTF8 utf8str(reinterpret_cast<const char16_t*>(chars),
   122                                   length);
   123 #ifdef ANDROID
   124     __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
   125 #endif
   126 #ifdef XP_WIN
   127     if (IsDebuggerPresent()) {
   128       OutputDebugStringW(reinterpret_cast<const wchar_t*>(chars));
   129     }
   130 #endif
   131     fputs(utf8str.get(), stdout);
   132     fflush(stdout);
   133     return true;
   134 }
   136 static bool
   137 Debug(JSContext *cx, unsigned argc, jsval *vp)
   138 {
   139 #ifdef DEBUG
   140     return Dump(cx, argc, vp);
   141 #else
   142     return true;
   143 #endif
   144 }
   146 static bool
   147 File(JSContext *cx, unsigned argc, Value *vp)
   148 {
   149     CallArgs args = CallArgsFromVp(argc, vp);
   151     if (args.length() == 0) {
   152         XPCThrower::Throw(NS_ERROR_UNEXPECTED, cx);
   153         return false;
   154     }
   156     nsCOMPtr<nsISupports> native;
   157     nsresult rv = nsDOMMultipartFile::NewFile(getter_AddRefs(native));
   158     if (NS_FAILED(rv)) {
   159         XPCThrower::Throw(rv, cx);
   160         return false;
   161     }
   163     nsCOMPtr<nsIJSNativeInitializer> initializer = do_QueryInterface(native);
   164     MOZ_ASSERT(initializer);
   166     rv = initializer->Initialize(nullptr, cx, nullptr, args);
   167     if (NS_FAILED(rv)) {
   168         XPCThrower::Throw(rv, cx);
   169         return false;
   170     }
   172     nsXPConnect *xpc = nsXPConnect::XPConnect();
   173     JSObject *glob = CurrentGlobalOrNull(cx);
   175     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   176     rv = xpc->WrapNativeToJSVal(cx, glob, native, nullptr,
   177                                 &NS_GET_IID(nsISupports),
   178                                 true, args.rval());
   179     if (NS_FAILED(rv)) {
   180         XPCThrower::Throw(rv, cx);
   181         return false;
   182     }
   183     return true;
   184 }
   186 static bool
   187 Blob(JSContext *cx, unsigned argc, Value *vp)
   188 {
   189     CallArgs args = CallArgsFromVp(argc, vp);
   191     nsCOMPtr<nsISupports> native;
   192     nsresult rv = nsDOMMultipartFile::NewBlob(getter_AddRefs(native));
   193     if (NS_FAILED(rv)) {
   194         XPCThrower::Throw(rv, cx);
   195         return false;
   196     }
   198     nsCOMPtr<nsIJSNativeInitializer> initializer = do_QueryInterface(native);
   199     MOZ_ASSERT(initializer);
   201     rv = initializer->Initialize(nullptr, cx, nullptr, args);
   202     if (NS_FAILED(rv)) {
   203         XPCThrower::Throw(rv, cx);
   204         return false;
   205     }
   207     nsXPConnect *xpc = nsXPConnect::XPConnect();
   208     JSObject *glob = CurrentGlobalOrNull(cx);
   210     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   211     rv = xpc->WrapNativeToJSVal(cx, glob, native, nullptr,
   212                                 &NS_GET_IID(nsISupports),
   213                                 true, args.rval());
   214     if (NS_FAILED(rv)) {
   215         XPCThrower::Throw(rv, cx);
   216         return false;
   217     }
   218     return true;
   219 }
   221 static const JSFunctionSpec gGlobalFun[] = {
   222     JS_FS("dump",    Dump,   1,0),
   223     JS_FS("debug",   Debug,  1,0),
   224     JS_FS("atob",    Atob,   1,0),
   225     JS_FS("btoa",    Btoa,   1,0),
   226     JS_FS("File",    File,   1,JSFUN_CONSTRUCTOR),
   227     JS_FS("Blob",    Blob,   2,JSFUN_CONSTRUCTOR),
   228     JS_FS_END
   229 };
   231 class MOZ_STACK_CLASS JSCLContextHelper
   232 {
   233 public:
   234     JSCLContextHelper(JSContext* aCx);
   235     ~JSCLContextHelper();
   237     void reportErrorAfterPop(char *buf);
   239     operator JSContext*() const {return mContext;}
   241 private:
   243     JSContext* mContext;
   244     nsCxPusher mPusher;
   245     char*      mBuf;
   247     // prevent copying and assignment
   248     JSCLContextHelper(const JSCLContextHelper &) MOZ_DELETE;
   249     const JSCLContextHelper& operator=(const JSCLContextHelper &) MOZ_DELETE;
   250 };
   253 class JSCLAutoErrorReporterSetter
   254 {
   255 public:
   256     JSCLAutoErrorReporterSetter(JSContext* cx, JSErrorReporter reporter)
   257         {mContext = cx; mOldReporter = JS_SetErrorReporter(cx, reporter);}
   258     ~JSCLAutoErrorReporterSetter()
   259         {JS_SetErrorReporter(mContext, mOldReporter);}
   260 private:
   261     JSContext* mContext;
   262     JSErrorReporter mOldReporter;
   264     JSCLAutoErrorReporterSetter(const JSCLAutoErrorReporterSetter &) MOZ_DELETE;
   265     const JSCLAutoErrorReporterSetter& operator=(const JSCLAutoErrorReporterSetter &) MOZ_DELETE;
   266 };
   268 static nsresult
   269 ReportOnCaller(JSContext *callerContext,
   270                const char *format, ...) {
   271     if (!callerContext) {
   272         return NS_ERROR_FAILURE;
   273     }
   275     va_list ap;
   276     va_start(ap, format);
   278     char *buf = JS_vsmprintf(format, ap);
   279     if (!buf) {
   280         return NS_ERROR_OUT_OF_MEMORY;
   281     }
   283     JS_ReportError(callerContext, buf);
   284     JS_smprintf_free(buf);
   286     return NS_OK;
   287 }
   289 static nsresult
   290 ReportOnCaller(JSCLContextHelper &helper,
   291                const char *format, ...)
   292 {
   293     va_list ap;
   294     va_start(ap, format);
   296     char *buf = JS_vsmprintf(format, ap);
   297     if (!buf) {
   298         return NS_ERROR_OUT_OF_MEMORY;
   299     }
   301     helper.reportErrorAfterPop(buf);
   303     return NS_OK;
   304 }
   306 mozJSComponentLoader::mozJSComponentLoader()
   307     : mRuntime(nullptr),
   308       mContext(nullptr),
   309       mModules(32),
   310       mImports(32),
   311       mInProgressImports(32),
   312       mThisObjects(32),
   313       mInitialized(false),
   314       mReuseLoaderGlobal(false)
   315 {
   316     MOZ_ASSERT(!sSelf, "mozJSComponentLoader should be a singleton");
   318 #ifdef PR_LOGGING
   319     if (!gJSCLLog) {
   320         gJSCLLog = PR_NewLogModule("JSComponentLoader");
   321     }
   322 #endif
   324     sSelf = this;
   325 }
   327 mozJSComponentLoader::~mozJSComponentLoader()
   328 {
   329     if (mInitialized) {
   330         NS_ERROR("'xpcom-shutdown-loaders' was not fired before cleaning up mozJSComponentLoader");
   331         UnloadModules();
   332     }
   334     sSelf = nullptr;
   335 }
   337 mozJSComponentLoader*
   338 mozJSComponentLoader::sSelf;
   340 NS_IMPL_ISUPPORTS(mozJSComponentLoader,
   341                   mozilla::ModuleLoader,
   342                   xpcIJSModuleLoader,
   343                   nsIObserver)
   345 nsresult
   346 mozJSComponentLoader::ReallyInit()
   347 {
   348     nsresult rv;
   350     mReuseLoaderGlobal = Preferences::GetBool("jsloader.reuseGlobal");
   352     // XXXkhuey B2G child processes have some sort of preferences race that
   353     // results in getting the wrong value.
   354 #ifdef MOZ_B2G
   355     mReuseLoaderGlobal = true;
   356 #endif
   358     /*
   359      * Get the JSRuntime from the runtime svc, if possible.
   360      * We keep a reference around, because it's a Bad Thing if the runtime
   361      * service gets shut down before we're done.  Bad!
   362      */
   364     mRuntimeService = do_GetService(kJSRuntimeServiceContractID, &rv);
   365     if (NS_FAILED(rv) ||
   366         NS_FAILED(rv = mRuntimeService->GetRuntime(&mRuntime)))
   367         return rv;
   369     // Create our compilation context.
   370     mContext = JS_NewContext(mRuntime, 256);
   371     if (!mContext)
   372         return NS_ERROR_OUT_OF_MEMORY;
   374     nsCOMPtr<nsIScriptSecurityManager> secman =
   375         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   376     if (!secman)
   377         return NS_ERROR_FAILURE;
   379     rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal));
   380     if (NS_FAILED(rv) || !mSystemPrincipal)
   381         return NS_ERROR_FAILURE;
   383     nsCOMPtr<nsIObserverService> obsSvc =
   384         do_GetService(kObserverServiceContractID, &rv);
   385     NS_ENSURE_SUCCESS(rv, rv);
   387     rv = obsSvc->AddObserver(this, "xpcom-shutdown-loaders", false);
   388     NS_ENSURE_SUCCESS(rv, rv);
   390     mInitialized = true;
   392     return NS_OK;
   393 }
   395 const mozilla::Module*
   396 mozJSComponentLoader::LoadModule(FileLocation &aFile)
   397 {
   398     nsCOMPtr<nsIFile> file = aFile.GetBaseFile();
   400     nsCString spec;
   401     aFile.GetURIString(spec);
   403     nsCOMPtr<nsIURI> uri;
   404     nsresult rv = NS_NewURI(getter_AddRefs(uri), spec);
   405     if (NS_FAILED(rv))
   406         return nullptr;
   408     if (!mInitialized) {
   409         rv = ReallyInit();
   410         if (NS_FAILED(rv))
   411             return nullptr;
   412     }
   414     ModuleEntry* mod;
   415     if (mModules.Get(spec, &mod))
   416     return mod;
   418     nsAutoPtr<ModuleEntry> entry(new ModuleEntry(mContext));
   420     JSAutoRequest ar(mContext);
   421     RootedValue dummy(mContext);
   422     rv = ObjectForLocation(file, uri, &entry->obj, &entry->thisObjectKey,
   423                            &entry->location, false, &dummy);
   424     if (NS_FAILED(rv)) {
   425         return nullptr;
   426     }
   428     nsCOMPtr<nsIXPConnect> xpc = do_GetService(kXPConnectServiceContractID,
   429                                                &rv);
   430     if (NS_FAILED(rv))
   431         return nullptr;
   433     nsCOMPtr<nsIComponentManager> cm;
   434     rv = NS_GetComponentManager(getter_AddRefs(cm));
   435     if (NS_FAILED(rv))
   436         return nullptr;
   438     JSCLContextHelper cx(mContext);
   439     JSAutoCompartment ac(cx, entry->obj);
   441     nsCOMPtr<nsIXPConnectJSObjectHolder> cm_holder;
   442     rv = xpc->WrapNative(cx, entry->obj, cm,
   443                          NS_GET_IID(nsIComponentManager),
   444                          getter_AddRefs(cm_holder));
   446     if (NS_FAILED(rv)) {
   447         return nullptr;
   448     }
   450     JSObject* cm_jsobj = cm_holder->GetJSObject();
   451     if (!cm_jsobj) {
   452         return nullptr;
   453     }
   455     nsCOMPtr<nsIXPConnectJSObjectHolder> file_holder;
   456     RootedObject entryObj(cx, entry->obj);
   457     rv = xpc->WrapNative(cx, entryObj, file,
   458                          NS_GET_IID(nsIFile),
   459                          getter_AddRefs(file_holder));
   461     if (NS_FAILED(rv)) {
   462         return nullptr;
   463     }
   465     JSObject* file_jsobj = file_holder->GetJSObject();
   466     if (!file_jsobj) {
   467         return nullptr;
   468     }
   470     JSCLAutoErrorReporterSetter aers(cx, xpc::SystemErrorReporter);
   472     RootedValue NSGetFactory_val(cx);
   473     if (!JS_GetProperty(cx, entryObj, "NSGetFactory", &NSGetFactory_val) ||
   474         JSVAL_IS_VOID(NSGetFactory_val)) {
   475         return nullptr;
   476     }
   478     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
   479         nsAutoCString spec;
   480         uri->GetSpec(spec);
   481         JS_ReportError(cx, "%s has NSGetFactory property that is not a function",
   482                        spec.get());
   483         return nullptr;
   484     }
   486     RootedObject jsGetFactoryObj(cx);
   487     if (!JS_ValueToObject(cx, NSGetFactory_val, &jsGetFactoryObj) ||
   488         !jsGetFactoryObj) {
   489         /* XXX report error properly */
   490         return nullptr;
   491     }
   493     rv = xpc->WrapJS(cx, jsGetFactoryObj,
   494                      NS_GET_IID(xpcIJSGetFactory), getter_AddRefs(entry->getfactoryobj));
   495     if (NS_FAILED(rv)) {
   496         /* XXX report error properly */
   497 #ifdef DEBUG
   498         fprintf(stderr, "mJCL: couldn't get nsIModule from jsval\n");
   499 #endif
   500         return nullptr;
   501     }
   503     // Cache this module for later
   504     mModules.Put(spec, entry);
   506     // Set the location information for the new global, so that tools like
   507     // about:memory may use that information
   508     if (!mReuseLoaderGlobal) {
   509         xpc::SetLocationForGlobal(entryObj, spec);
   510     }
   512     // The hash owns the ModuleEntry now, forget about it
   513     return entry.forget();
   514 }
   516 nsresult
   517 mozJSComponentLoader::FindTargetObject(JSContext* aCx,
   518                                        MutableHandleObject aTargetObject)
   519 {
   520     aTargetObject.set(nullptr);
   522     RootedObject targetObject(aCx);
   523     if (mReuseLoaderGlobal) {
   524         JSScript* script =
   525             js::GetOutermostEnclosingFunctionOfScriptedCaller(aCx);
   526         if (script) {
   527             targetObject = mThisObjects.Get(script);
   528         }
   529     }
   531     // The above could fail, even if mReuseLoaderGlobal, if the scripted
   532     // caller is not a component/JSM (it could be a DOM scope, for
   533     // instance).
   534     if (!targetObject) {
   535         // Our targetObject is the caller's global object. Let's get it.
   536         nsresult rv;
   537         nsCOMPtr<nsIXPConnect> xpc =
   538             do_GetService(kXPConnectServiceContractID, &rv);
   539         NS_ENSURE_SUCCESS(rv, rv);
   541         nsAXPCNativeCallContext *cc = nullptr;
   542         rv = xpc->GetCurrentNativeCallContext(&cc);
   543         NS_ENSURE_SUCCESS(rv, rv);
   545         nsCOMPtr<nsIXPConnectWrappedNative> wn;
   546         rv = cc->GetCalleeWrapper(getter_AddRefs(wn));
   547         NS_ENSURE_SUCCESS(rv, rv);
   549         targetObject = wn->GetJSObject();
   550         if (!targetObject) {
   551             NS_ERROR("null calling object");
   552             return NS_ERROR_FAILURE;
   553         }
   555         targetObject = JS_GetGlobalForObject(aCx, targetObject);
   556     }
   558     aTargetObject.set(targetObject);
   559     return NS_OK;
   560 }
   562 void
   563 mozJSComponentLoader::NoteSubScript(HandleScript aScript, HandleObject aThisObject)
   564 {
   565   if (!mInitialized && NS_FAILED(ReallyInit())) {
   566       MOZ_CRASH();
   567   }
   569   if (js::GetObjectJSClass(aThisObject) == &kFakeBackstagePassJSClass) {
   570     mThisObjects.Put(aScript, aThisObject);
   571   }
   572 }
   574 /* static */ size_t
   575 mozJSComponentLoader::DataEntrySizeOfExcludingThis(const nsACString& aKey,
   576                                                    ModuleEntry* const& aData,
   577                                                    MallocSizeOf aMallocSizeOf, void*)
   578 {
   579     return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
   580         aData->SizeOfIncludingThis(aMallocSizeOf);
   581 }
   583 /* static */ size_t
   584 mozJSComponentLoader::ClassEntrySizeOfExcludingThis(const nsACString& aKey,
   585                                                     const nsAutoPtr<ModuleEntry>& aData,
   586                                                     MallocSizeOf aMallocSizeOf, void*)
   587 {
   588     return aKey.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
   589         aData->SizeOfIncludingThis(aMallocSizeOf);
   590 }
   592 size_t
   593 mozJSComponentLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)
   594 {
   595     size_t amount = aMallocSizeOf(this);
   597     amount += mModules.SizeOfExcludingThis(DataEntrySizeOfExcludingThis, aMallocSizeOf);
   598     amount += mImports.SizeOfExcludingThis(ClassEntrySizeOfExcludingThis, aMallocSizeOf);
   599     amount += mInProgressImports.SizeOfExcludingThis(DataEntrySizeOfExcludingThis, aMallocSizeOf);
   600     amount += mThisObjects.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   602     return amount;
   603 }
   605 // Some stack based classes for cleaning up on early return
   606 #ifdef HAVE_PR_MEMMAP
   607 class FileAutoCloser
   608 {
   609  public:
   610     explicit FileAutoCloser(PRFileDesc *file) : mFile(file) {}
   611     ~FileAutoCloser() { PR_Close(mFile); }
   612  private:
   613     PRFileDesc *mFile;
   614 };
   616 class FileMapAutoCloser
   617 {
   618  public:
   619     explicit FileMapAutoCloser(PRFileMap *map) : mMap(map) {}
   620     ~FileMapAutoCloser() { PR_CloseFileMap(mMap); }
   621  private:
   622     PRFileMap *mMap;
   623 };
   624 #else
   625 class ANSIFileAutoCloser
   626 {
   627  public:
   628     explicit ANSIFileAutoCloser(FILE *file) : mFile(file) {}
   629     ~ANSIFileAutoCloser() { fclose(mFile); }
   630  private:
   631     FILE *mFile;
   632 };
   633 #endif
   635 JSObject*
   636 mozJSComponentLoader::PrepareObjectForLocation(JSCLContextHelper& aCx,
   637                                                nsIFile *aComponentFile,
   638                                                nsIURI *aURI,
   639                                                bool aReuseLoaderGlobal,
   640                                                bool *aRealFile)
   641 {
   642     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
   643     if (aReuseLoaderGlobal) {
   644         holder = mLoaderGlobal;
   645     }
   647     nsresult rv = NS_OK;
   648     nsCOMPtr<nsIXPConnect> xpc =
   649         do_GetService(kXPConnectServiceContractID, &rv);
   650     NS_ENSURE_SUCCESS(rv, nullptr);
   651     bool createdNewGlobal = false;
   653     if (!mLoaderGlobal) {
   654         nsRefPtr<BackstagePass> backstagePass;
   655         rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
   656         NS_ENSURE_SUCCESS(rv, nullptr);
   658         CompartmentOptions options;
   659         options.setZone(SystemZone)
   660                .setVersion(JSVERSION_LATEST);
   661         // Defer firing OnNewGlobalObject until after the __URI__ property has
   662         // been defined so the JS debugger can tell what module the global is
   663         // for
   664         rv = xpc->InitClassesWithNewWrappedGlobal(aCx,
   665                                                   static_cast<nsIGlobalObject *>(backstagePass),
   666                                                   mSystemPrincipal,
   667                                                   nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK,
   668                                                   options,
   669                                                   getter_AddRefs(holder));
   670         NS_ENSURE_SUCCESS(rv, nullptr);
   671         createdNewGlobal = true;
   673         RootedObject global(aCx, holder->GetJSObject());
   674         NS_ENSURE_TRUE(global, nullptr);
   676         backstagePass->SetGlobalObject(global);
   678         JSAutoCompartment ac(aCx, global);
   679         if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
   680             !JS_DefineProfilingFunctions(aCx, global)) {
   681             return nullptr;
   682         }
   684         if (aReuseLoaderGlobal) {
   685             mLoaderGlobal = holder;
   686         }
   687     }
   689     RootedObject obj(aCx, holder->GetJSObject());
   690     NS_ENSURE_TRUE(obj, nullptr);
   692     JSAutoCompartment ac(aCx, obj);
   694     if (aReuseLoaderGlobal) {
   695         // If we're reusing the loader global, we don't actually use the
   696         // global, but rather we use a different object as the 'this' object.
   697         obj = JS_NewObject(aCx, &kFakeBackstagePassJSClass, NullPtr(), NullPtr());
   698         NS_ENSURE_TRUE(obj, nullptr);
   699     }
   701     *aRealFile = false;
   703     // need to be extra careful checking for URIs pointing to files
   704     // EnsureFile may not always get called, especially on resource URIs
   705     // so we need to call GetFile to make sure this is a valid file
   706     nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
   707     nsCOMPtr<nsIFile> testFile;
   708     if (NS_SUCCEEDED(rv)) {
   709         fileURL->GetFile(getter_AddRefs(testFile));
   710     }
   712     if (testFile) {
   713         *aRealFile = true;
   715         nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
   716         rv = xpc->WrapNative(aCx, obj, aComponentFile,
   717                              NS_GET_IID(nsIFile),
   718                              getter_AddRefs(locationHolder));
   719         NS_ENSURE_SUCCESS(rv, nullptr);
   721         RootedObject locationObj(aCx, locationHolder->GetJSObject());
   722         NS_ENSURE_TRUE(locationObj, nullptr);
   724         if (!JS_DefineProperty(aCx, obj, "__LOCATION__", locationObj, 0))
   725             return nullptr;
   726     }
   728     nsAutoCString nativePath;
   729     rv = aURI->GetSpec(nativePath);
   730     NS_ENSURE_SUCCESS(rv, nullptr);
   732     // Expose the URI from which the script was imported through a special
   733     // variable that we insert into the JSM.
   734     RootedString exposedUri(aCx, JS_NewStringCopyN(aCx, nativePath.get(), nativePath.Length()));
   735     NS_ENSURE_TRUE(exposedUri, nullptr);
   737     if (!JS_DefineProperty(aCx, obj, "__URI__", exposedUri, 0))
   738         return nullptr;
   740     if (createdNewGlobal) {
   741         RootedObject global(aCx, holder->GetJSObject());
   742         JS_FireOnNewGlobalObject(aCx, global);
   743     }
   745     return obj;
   746 }
   748 nsresult
   749 mozJSComponentLoader::ObjectForLocation(nsIFile *aComponentFile,
   750                                         nsIURI *aURI,
   751                                         MutableHandleObject aObject,
   752                                         MutableHandleScript aTableScript,
   753                                         char **aLocation,
   754                                         bool aPropagateExceptions,
   755                                         MutableHandleValue aException)
   756 {
   757     JSCLContextHelper cx(mContext);
   759     JS_AbortIfWrongThread(JS_GetRuntime(cx));
   761     JSCLAutoErrorReporterSetter aers(cx, xpc::SystemErrorReporter);
   763     bool realFile = false;
   764     RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aURI,
   765                                                   mReuseLoaderGlobal, &realFile));
   766     NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
   768     JSAutoCompartment ac(cx, obj);
   770     RootedScript script(cx);
   771     RootedFunction function(cx);
   773     nsAutoCString nativePath;
   774     nsresult rv = aURI->GetSpec(nativePath);
   775     NS_ENSURE_SUCCESS(rv, rv);
   777     // Before compiling the script, first check to see if we have it in
   778     // the startupcache.  Note: as a rule, startupcache errors are not fatal
   779     // to loading the script, since we can always slow-load.
   781     bool writeToCache = false;
   782     StartupCache* cache = StartupCache::GetSingleton();
   784     nsAutoCString cachePath(kJSCachePrefix);
   785     rv = PathifyURI(aURI, cachePath);
   786     NS_ENSURE_SUCCESS(rv, rv);
   788     if (cache) {
   789         if (!mReuseLoaderGlobal) {
   790             rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script);
   791         } else {
   792             rv = ReadCachedFunction(cache, cachePath, cx, mSystemPrincipal,
   793                                     function.address());
   794         }
   796         if (NS_SUCCEEDED(rv)) {
   797             LOG(("Successfully loaded %s from startupcache\n", nativePath.get()));
   798         } else {
   799             // This is ok, it just means the script is not yet in the
   800             // cache. Could mean that the cache was corrupted and got removed,
   801             // but either way we're going to write this out.
   802             writeToCache = true;
   803         }
   804     }
   806     if (!script && !function) {
   807         // The script wasn't in the cache , so compile it now.
   808         LOG(("Slow loading %s\n", nativePath.get()));
   810         // If aPropagateExceptions is true, then our caller wants us to propagate
   811         // any exceptions out to our caller. Ensure that the engine doesn't
   812         // eagerly report the exception.
   813         AutoSaveContextOptions asco(cx);
   814         if (aPropagateExceptions)
   815             ContextOptionsRef(cx).setDontReportUncaught(true);
   817         // Note - if mReuseLoaderGlobal is true, then we can't do lazy source,
   818         // because we compile things as functions (rather than script), and lazy
   819         // source isn't supported in that configuration. That's ok though,
   820         // because we only do mReuseLoaderGlobal on b2g, where we invoke
   821         // setDiscardSource(true) on the entire global.
   822         CompileOptions options(cx);
   823         options.setNoScriptRval(mReuseLoaderGlobal ? false : true)
   824                .setVersion(JSVERSION_LATEST)
   825                .setFileAndLine(nativePath.get(), 1)
   826                .setSourceIsLazy(!mReuseLoaderGlobal);
   828         if (realFile) {
   829 #ifdef HAVE_PR_MEMMAP
   830             int64_t fileSize;
   831             rv = aComponentFile->GetFileSize(&fileSize);
   832             if (NS_FAILED(rv)) {
   833                 return rv;
   834             }
   836             int64_t maxSize = UINT32_MAX;
   837             if (fileSize > maxSize) {
   838                 NS_ERROR("file too large");
   839                 return NS_ERROR_FAILURE;
   840             }
   842             PRFileDesc *fileHandle;
   843             rv = aComponentFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
   844             if (NS_FAILED(rv)) {
   845                 return NS_ERROR_FILE_NOT_FOUND;
   846             }
   848             // Make sure the file is closed, no matter how we return.
   849             FileAutoCloser fileCloser(fileHandle);
   851             // We don't provide the file size here.  If we did, PR_CreateFileMap
   852             // would simply stat() the file to verify that the size we provided
   853             // didn't require extending the file.  We know that the file doesn't
   854             // need to be extended, so skip the extra work by not providing the
   855             // size.
   856             PRFileMap *map = PR_CreateFileMap(fileHandle, 0, PR_PROT_READONLY);
   857             if (!map) {
   858                 NS_ERROR("Failed to create file map");
   859                 return NS_ERROR_FAILURE;
   860             }
   862             // Make sure the file map is closed, no matter how we return.
   863             FileMapAutoCloser mapCloser(map);
   865             uint32_t fileSize32 = fileSize;
   867             char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
   868             if (!buf) {
   869                 NS_WARNING("Failed to map file");
   870                 return NS_ERROR_FAILURE;
   871             }
   873             if (!mReuseLoaderGlobal) {
   874                 script = Compile(cx, obj, options, buf,
   875                                      fileSize32);
   876             } else {
   877                 function = CompileFunction(cx, obj, options,
   878                                                nullptr, 0, nullptr,
   879                                                buf, fileSize32);
   880             }
   882             PR_MemUnmap(buf, fileSize32);
   884 #else  /* HAVE_PR_MEMMAP */
   886             /**
   887              * No memmap implementation, so fall back to
   888              * reading in the file
   889              */
   891             FILE *fileHandle;
   892             rv = aComponentFile->OpenANSIFileDesc("r", &fileHandle);
   893             if (NS_FAILED(rv)) {
   894                 return NS_ERROR_FILE_NOT_FOUND;
   895             }
   897             // Ensure file fclose
   898             ANSIFileAutoCloser fileCloser(fileHandle);
   900             int64_t len;
   901             rv = aComponentFile->GetFileSize(&len);
   902             if (NS_FAILED(rv) || len < 0) {
   903                 NS_WARNING("Failed to get file size");
   904                 return NS_ERROR_FAILURE;
   905             }
   907             char *buf = (char *) malloc(len * sizeof(char));
   908             if (!buf) {
   909                 return NS_ERROR_FAILURE;
   910             }
   912             size_t rlen = fread(buf, 1, len, fileHandle);
   913             if (rlen != (uint64_t)len) {
   914                 free(buf);
   915                 NS_WARNING("Failed to read file");
   916                 return NS_ERROR_FAILURE;
   917             }
   919             if (!mReuseLoaderGlobal) {
   920                 script = Compile(cx, obj, options, buf,
   921                                      fileSize32);
   922             } else {
   923                 function = CompileFunction(cx, obj, options,
   924                                            nullptr, 0, nullptr,
   925                                            buf, fileSize32);
   926             }
   928             free(buf);
   930 #endif /* HAVE_PR_MEMMAP */
   931         } else {
   932             nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   933             NS_ENSURE_SUCCESS(rv, rv);
   935             nsCOMPtr<nsIChannel> scriptChannel;
   936             rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(scriptChannel));
   937             NS_ENSURE_SUCCESS(rv, rv);
   939             nsCOMPtr<nsIInputStream> scriptStream;
   940             rv = scriptChannel->Open(getter_AddRefs(scriptStream));
   941             NS_ENSURE_SUCCESS(rv, rv);
   943             uint64_t len64;
   944             uint32_t bytesRead;
   946             rv = scriptStream->Available(&len64);
   947             NS_ENSURE_SUCCESS(rv, rv);
   948             NS_ENSURE_TRUE(len64 < UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
   949             if (!len64)
   950                 return NS_ERROR_FAILURE;
   951             uint32_t len = (uint32_t)len64;
   953             /* malloc an internal buf the size of the file */
   954             nsAutoArrayPtr<char> buf(new char[len + 1]);
   955             if (!buf)
   956                 return NS_ERROR_OUT_OF_MEMORY;
   958             /* read the file in one swoop */
   959             rv = scriptStream->Read(buf, len, &bytesRead);
   960             if (bytesRead != len)
   961                 return NS_BASE_STREAM_OSERROR;
   963             buf[len] = '\0';
   965             if (!mReuseLoaderGlobal) {
   966                 script = Compile(cx, obj, options, buf, bytesRead);
   967             } else {
   968                 function = CompileFunction(cx, obj, options,
   969                                                nullptr, 0, nullptr,
   970                                                buf, bytesRead);
   971             }
   972         }
   973         // Propagate the exception, if one exists. Also, don't leave the stale
   974         // exception on this context.
   975         if (!script && !function && aPropagateExceptions) {
   976             JS_GetPendingException(cx, aException);
   977             JS_ClearPendingException(cx);
   978         }
   979     }
   981     if (!script && !function) {
   982         return NS_ERROR_FAILURE;
   983     }
   985     if (writeToCache) {
   986         // We successfully compiled the script, so cache it.
   987         if (script) {
   988             rv = WriteCachedScript(cache, cachePath, cx, mSystemPrincipal,
   989                                    script);
   990         } else {
   991             rv = WriteCachedFunction(cache, cachePath, cx, mSystemPrincipal,
   992                                      function);
   993         }
   995         // Don't treat failure to write as fatal, since we might be working
   996         // with a read-only cache.
   997         if (NS_SUCCEEDED(rv)) {
   998             LOG(("Successfully wrote to cache\n"));
   999         } else {
  1000             LOG(("Failed to write to cache\n"));
  1004     // Assign aObject here so that it's available to recursive imports.
  1005     // See bug 384168.
  1006     aObject.set(obj);
  1008     RootedScript tableScript(cx, script);
  1009     if (!tableScript) {
  1010         tableScript = JS_GetFunctionScript(cx, function);
  1011         MOZ_ASSERT(tableScript);
  1014     aTableScript.set(tableScript);
  1016     if (js::GetObjectJSClass(obj) == &kFakeBackstagePassJSClass) {
  1017         MOZ_ASSERT(mReuseLoaderGlobal);
  1018         // tableScript stays in the table until shutdown.  It is rooted by
  1019         // virtue of the fact that aTableScript is a handle to
  1020         // ModuleEntry::thisObjectKey, which is a PersistentRootedScript.  Since
  1021         // ModuleEntries are never dynamically unloaded when mReuseLoaderGlobal
  1022         // is true, this prevents it from being collected and another script
  1023         // getting the same address.
  1024         mThisObjects.Put(tableScript, obj);
  1026     bool ok = false;
  1029         AutoSaveContextOptions asco(cx);
  1030         if (aPropagateExceptions)
  1031             ContextOptionsRef(cx).setDontReportUncaught(true);
  1032         if (script) {
  1033             ok = JS_ExecuteScriptVersion(cx, obj, script, JSVERSION_LATEST);
  1034         } else {
  1035             RootedValue rval(cx);
  1036             ok = JS_CallFunction(cx, obj, function, JS::HandleValueArray::empty(), &rval);
  1040     if (!ok) {
  1041         if (aPropagateExceptions) {
  1042             JS_GetPendingException(cx, aException);
  1043             JS_ClearPendingException(cx);
  1045         aObject.set(nullptr);
  1046         aTableScript.set(nullptr);
  1047         mThisObjects.Remove(tableScript);
  1048         return NS_ERROR_FAILURE;
  1051     /* Freed when we remove from the table. */
  1052     *aLocation = ToNewCString(nativePath);
  1053     if (!*aLocation) {
  1054         aObject.set(nullptr);
  1055         aTableScript.set(nullptr);
  1056         mThisObjects.Remove(tableScript);
  1057         return NS_ERROR_OUT_OF_MEMORY;
  1060     return NS_OK;
  1063 /* static */ PLDHashOperator
  1064 mozJSComponentLoader::ClearModules(const nsACString& key, ModuleEntry*& entry, void* cx)
  1066     entry->Clear();
  1067     return PL_DHASH_REMOVE;
  1070 void
  1071 mozJSComponentLoader::UnloadModules()
  1073     mInitialized = false;
  1075     if (mLoaderGlobal) {
  1076         MOZ_ASSERT(mReuseLoaderGlobal, "How did this happen?");
  1078         JSAutoRequest ar(mContext);
  1079         RootedObject global(mContext, mLoaderGlobal->GetJSObject());
  1080         if (global) {
  1081             JSAutoCompartment ac(mContext, global);
  1082             JS_SetAllNonReservedSlotsToUndefined(mContext, global);
  1083         } else {
  1084             NS_WARNING("Going to leak!");
  1087         mLoaderGlobal = nullptr;
  1090     mInProgressImports.Clear();
  1091     mImports.Clear();
  1092     mThisObjects.Clear();
  1094     mModules.Enumerate(ClearModules, nullptr);
  1096     JS_DestroyContextNoGC(mContext);
  1097     mContext = nullptr;
  1099     mRuntimeService = nullptr;
  1102 NS_IMETHODIMP
  1103 mozJSComponentLoader::Import(const nsACString& registryLocation,
  1104                              HandleValue targetValArg,
  1105                              JSContext *cx,
  1106                              uint8_t optionalArgc,
  1107                              MutableHandleValue retval)
  1109     MOZ_ASSERT(nsContentUtils::IsCallerChrome());
  1111     RootedValue targetVal(cx, targetValArg);
  1112     RootedObject targetObject(cx, nullptr);
  1113     if (optionalArgc) {
  1114         // The caller passed in the optional second argument. Get it.
  1115         if (targetVal.isObject()) {
  1116             // If we're passing in something like a content DOM window, chances
  1117             // are the caller expects the properties to end up on the object
  1118             // proper and not on the Xray holder. This is dubious, but can be used
  1119             // during testing. Given that dumb callers can already leak JSMs into
  1120             // content by passing a raw content JS object (where Xrays aren't
  1121             // possible), we aim for consistency here. Waive xray.
  1122             if (WrapperFactory::IsXrayWrapper(&targetVal.toObject()) &&
  1123                 !WrapperFactory::WaiveXrayAndWrap(cx, &targetVal))
  1125                 return NS_ERROR_FAILURE;
  1127             targetObject = &targetVal.toObject();
  1128         } else if (!targetVal.isNull()) {
  1129             // If targetVal isNull(), we actually want to leave targetObject null.
  1130             // Not doing so breaks |make package|.
  1131             return ReportOnCaller(cx, ERROR_SCOPE_OBJ,
  1132                                   PromiseFlatCString(registryLocation).get());
  1134     } else {
  1135         nsresult rv = FindTargetObject(cx, &targetObject);
  1136         NS_ENSURE_SUCCESS(rv, rv);
  1139     Maybe<JSAutoCompartment> ac;
  1140     if (targetObject) {
  1141         ac.construct(cx, targetObject);
  1144     RootedObject global(cx);
  1145     nsresult rv = ImportInto(registryLocation, targetObject, cx, &global);
  1147     if (global) {
  1148         if (!JS_WrapObject(cx, &global)) {
  1149             NS_ERROR("can't wrap return value");
  1150             return NS_ERROR_FAILURE;
  1153         retval.setObject(*global);
  1155     return rv;
  1158 /* [noscript] JSObjectPtr importInto(in AUTF8String registryLocation,
  1159                                      in JSObjectPtr targetObj); */
  1160 NS_IMETHODIMP
  1161 mozJSComponentLoader::ImportInto(const nsACString &aLocation,
  1162                                  JSObject *aTargetObj,
  1163                                  nsAXPCNativeCallContext *cc,
  1164                                  JSObject **_retval)
  1166     JSContext *callercx;
  1167     nsresult rv = cc->GetJSContext(&callercx);
  1168     NS_ENSURE_SUCCESS(rv, rv);
  1170     RootedObject targetObject(callercx, aTargetObj);
  1171     RootedObject global(callercx);
  1172     rv = ImportInto(aLocation, targetObject, callercx, &global);
  1173     NS_ENSURE_SUCCESS(rv, rv);
  1174     *_retval = global;
  1175     return NS_OK;
  1178 nsresult
  1179 mozJSComponentLoader::ImportInto(const nsACString &aLocation,
  1180                                  HandleObject targetObj,
  1181                                  JSContext *callercx,
  1182                                  MutableHandleObject vp)
  1184     vp.set(nullptr);
  1186     nsresult rv;
  1187     if (!mInitialized) {
  1188         rv = ReallyInit();
  1189         NS_ENSURE_SUCCESS(rv, rv);
  1192     nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
  1193     NS_ENSURE_SUCCESS(rv, rv);
  1195     // Get the URI.
  1196     nsCOMPtr<nsIURI> resURI;
  1197     rv = ioService->NewURI(aLocation, nullptr, nullptr, getter_AddRefs(resURI));
  1198     NS_ENSURE_SUCCESS(rv, rv);
  1200     // figure out the resolved URI
  1201     nsCOMPtr<nsIChannel> scriptChannel;
  1202     rv = ioService->NewChannelFromURI(resURI, getter_AddRefs(scriptChannel));
  1203     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
  1205     nsCOMPtr<nsIURI> resolvedURI;
  1206     rv = scriptChannel->GetURI(getter_AddRefs(resolvedURI));
  1207     NS_ENSURE_SUCCESS(rv, rv);
  1209     // get the JAR if there is one
  1210     nsCOMPtr<nsIJARURI> jarURI;
  1211     jarURI = do_QueryInterface(resolvedURI, &rv);
  1212     nsCOMPtr<nsIFileURL> baseFileURL;
  1213     if (NS_SUCCEEDED(rv)) {
  1214         nsCOMPtr<nsIURI> baseURI;
  1215         while (jarURI) {
  1216             jarURI->GetJARFile(getter_AddRefs(baseURI));
  1217             jarURI = do_QueryInterface(baseURI, &rv);
  1219         baseFileURL = do_QueryInterface(baseURI, &rv);
  1220         NS_ENSURE_SUCCESS(rv, rv);
  1221     } else {
  1222         baseFileURL = do_QueryInterface(resolvedURI, &rv);
  1223         NS_ENSURE_SUCCESS(rv, rv);
  1226     nsCOMPtr<nsIFile> sourceFile;
  1227     rv = baseFileURL->GetFile(getter_AddRefs(sourceFile));
  1228     NS_ENSURE_SUCCESS(rv, rv);
  1230     nsCOMPtr<nsIFile> sourceLocalFile;
  1231     sourceLocalFile = do_QueryInterface(sourceFile, &rv);
  1232     NS_ENSURE_SUCCESS(rv, rv);
  1234     nsAutoCString key;
  1235     rv = resolvedURI->GetSpec(key);
  1236     NS_ENSURE_SUCCESS(rv, rv);
  1238     ModuleEntry* mod;
  1239     nsAutoPtr<ModuleEntry> newEntry;
  1240     if (!mImports.Get(key, &mod) && !mInProgressImports.Get(key, &mod)) {
  1241         newEntry = new ModuleEntry(callercx);
  1242         if (!newEntry)
  1243             return NS_ERROR_OUT_OF_MEMORY;
  1244         mInProgressImports.Put(key, newEntry);
  1246         RootedValue exception(callercx);
  1247         rv = ObjectForLocation(sourceLocalFile, resURI, &newEntry->obj,
  1248                                &newEntry->thisObjectKey,
  1249                                &newEntry->location, true, &exception);
  1251         mInProgressImports.Remove(key);
  1253         if (NS_FAILED(rv)) {
  1254             if (!exception.isUndefined()) {
  1255                 // An exception was thrown during compilation. Propagate it
  1256                 // out to our caller so they can report it.
  1257                 if (!JS_WrapValue(callercx, &exception))
  1258                     return NS_ERROR_OUT_OF_MEMORY;
  1259                 JS_SetPendingException(callercx, exception);
  1260                 return NS_OK;
  1263             // Something failed, but we don't know what it is, guess.
  1264             return NS_ERROR_FILE_NOT_FOUND;
  1267         // Set the location information for the new global, so that tools like
  1268         // about:memory may use that information
  1269         if (!mReuseLoaderGlobal) {
  1270             xpc::SetLocationForGlobal(newEntry->obj, aLocation);
  1273         mod = newEntry;
  1276     MOZ_ASSERT(mod->obj, "Import table contains entry with no object");
  1277     vp.set(mod->obj);
  1279     if (targetObj) {
  1280         JSCLContextHelper cxhelper(mContext);
  1281         JSAutoCompartment ac(mContext, mod->obj);
  1283         RootedValue symbols(mContext);
  1284         RootedObject modObj(mContext, mod->obj);
  1285         if (!JS_GetProperty(mContext, modObj,
  1286                             "EXPORTED_SYMBOLS", &symbols)) {
  1287             return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT,
  1288                                   PromiseFlatCString(aLocation).get());
  1291         if (!JS_IsArrayObject(mContext, symbols)) {
  1292             return ReportOnCaller(cxhelper, ERROR_NOT_AN_ARRAY,
  1293                                   PromiseFlatCString(aLocation).get());
  1296         RootedObject symbolsObj(mContext, &symbols.toObject());
  1298         // Iterate over symbols array, installing symbols on targetObj:
  1300         uint32_t symbolCount = 0;
  1301         if (!JS_GetArrayLength(mContext, symbolsObj, &symbolCount)) {
  1302             return ReportOnCaller(cxhelper, ERROR_GETTING_ARRAY_LENGTH,
  1303                                   PromiseFlatCString(aLocation).get());
  1306 #ifdef DEBUG
  1307         nsAutoCString logBuffer;
  1308 #endif
  1310         RootedValue value(mContext);
  1311         RootedId symbolId(mContext);
  1312         for (uint32_t i = 0; i < symbolCount; ++i) {
  1313             if (!JS_GetElement(mContext, symbolsObj, i, &value) ||
  1314                 !value.isString() ||
  1315                 !JS_ValueToId(mContext, value, &symbolId)) {
  1316                 return ReportOnCaller(cxhelper, ERROR_ARRAY_ELEMENT,
  1317                                       PromiseFlatCString(aLocation).get(), i);
  1320             RootedObject modObj(mContext, mod->obj);
  1321             if (!JS_GetPropertyById(mContext, modObj, symbolId, &value)) {
  1322                 JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
  1323                 if (!bytes)
  1324                     return NS_ERROR_FAILURE;
  1325                 return ReportOnCaller(cxhelper, ERROR_GETTING_SYMBOL,
  1326                                       PromiseFlatCString(aLocation).get(),
  1327                                       bytes.ptr());
  1330             JSAutoCompartment target_ac(mContext, targetObj);
  1332             if (!JS_WrapValue(mContext, &value) ||
  1333                 !JS_SetPropertyById(mContext, targetObj, symbolId, value)) {
  1334                 JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
  1335                 if (!bytes)
  1336                     return NS_ERROR_FAILURE;
  1337                 return ReportOnCaller(cxhelper, ERROR_SETTING_SYMBOL,
  1338                                       PromiseFlatCString(aLocation).get(),
  1339                                       bytes.ptr());
  1341 #ifdef DEBUG
  1342             if (i == 0) {
  1343                 logBuffer.AssignLiteral("Installing symbols [ ");
  1345             JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
  1346             if (!!bytes)
  1347                 logBuffer.Append(bytes.ptr());
  1348             logBuffer.AppendLiteral(" ");
  1349             if (i == symbolCount - 1) {
  1350                 LOG(("%s] from %s\n", logBuffer.get(),
  1351                      PromiseFlatCString(aLocation).get()));
  1353 #endif
  1357     // Cache this module for later
  1358     if (newEntry) {
  1359         mImports.Put(key, newEntry);
  1360         newEntry.forget();
  1363     return NS_OK;
  1366 NS_IMETHODIMP
  1367 mozJSComponentLoader::Unload(const nsACString & aLocation)
  1369     nsresult rv;
  1371     if (!mInitialized) {
  1372         return NS_OK;
  1375     nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
  1376     NS_ENSURE_SUCCESS(rv, rv);
  1378     // Get the URI.
  1379     nsCOMPtr<nsIURI> resURI;
  1380     rv = ioService->NewURI(aLocation, nullptr, nullptr, getter_AddRefs(resURI));
  1381     NS_ENSURE_SUCCESS(rv, rv);
  1383     // figure out the resolved URI
  1384     nsCOMPtr<nsIChannel> scriptChannel;
  1385     rv = ioService->NewChannelFromURI(resURI, getter_AddRefs(scriptChannel));
  1386     NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG);
  1388     nsCOMPtr<nsIURI> resolvedURI;
  1389     rv = scriptChannel->GetURI(getter_AddRefs(resolvedURI));
  1390     NS_ENSURE_SUCCESS(rv, rv);
  1392     nsAutoCString key;
  1393     rv = resolvedURI->GetSpec(key);
  1394     NS_ENSURE_SUCCESS(rv, rv);
  1396     ModuleEntry* mod;
  1397     if (mImports.Get(key, &mod)) {
  1398         mImports.Remove(key);
  1401     return NS_OK;
  1404 NS_IMETHODIMP
  1405 mozJSComponentLoader::Observe(nsISupports *subject, const char *topic,
  1406                               const char16_t *data)
  1408     if (!strcmp(topic, "xpcom-shutdown-loaders")) {
  1409         UnloadModules();
  1410     } else {
  1411         NS_ERROR("Unexpected observer topic.");
  1414     return NS_OK;
  1417 size_t
  1418 mozJSComponentLoader::ModuleEntry::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  1420     size_t n = aMallocSizeOf(this);
  1421     n += aMallocSizeOf(location);
  1423     return n;
  1426 /* static */ already_AddRefed<nsIFactory>
  1427 mozJSComponentLoader::ModuleEntry::GetFactory(const mozilla::Module& module,
  1428                                               const mozilla::Module::CIDEntry& entry)
  1430     const ModuleEntry& self = static_cast<const ModuleEntry&>(module);
  1431     MOZ_ASSERT(self.getfactoryobj, "Handing out an uninitialized module?");
  1433     nsCOMPtr<nsIFactory> f;
  1434     nsresult rv = self.getfactoryobj->Get(*entry.cid, getter_AddRefs(f));
  1435     if (NS_FAILED(rv))
  1436         return nullptr;
  1438     return f.forget();
  1441 //----------------------------------------------------------------------
  1443 JSCLContextHelper::JSCLContextHelper(JSContext* aCx)
  1444     : mContext(aCx)
  1445     , mBuf(nullptr)
  1447     mPusher.Push(mContext);
  1448     JS_BeginRequest(mContext);
  1451 JSCLContextHelper::~JSCLContextHelper()
  1453     JS_EndRequest(mContext);
  1454     mPusher.Pop();
  1455     JSContext *restoredCx = nsContentUtils::GetCurrentJSContext();
  1456     if (restoredCx && mBuf) {
  1457         JS_ReportError(restoredCx, mBuf);
  1460     if (mBuf) {
  1461         JS_smprintf_free(mBuf);
  1465 void
  1466 JSCLContextHelper::reportErrorAfterPop(char *buf)
  1468     MOZ_ASSERT(!mBuf, "Already called reportErrorAfterPop");
  1469     mBuf = buf;

mercurial