tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mozJSModuleLoader.cpp (36388B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      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 "ScriptLoadRequest.h"
      8 #include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_ASSERT_IF
      9 #include "mozilla/Attributes.h"
     10 #include "mozilla/RefPtr.h"  // RefPtr, mozilla::StaticRefPtr
     11 #include "mozilla/Utf8.h"    // mozilla::Utf8Unit
     12 
     13 #include "mozilla/Logging.h"
     14 #include "mozilla/dom/RequestBinding.h"
     15 #ifdef ANDROID
     16 #  include <android/log.h>
     17 #endif
     18 #ifdef XP_WIN
     19 #  include <windows.h>
     20 #endif
     21 
     22 #include "jsapi.h"
     23 #include "js/Array.h"  // JS::GetArrayLength, JS::IsArrayObject
     24 #include "js/CharacterEncoding.h"
     25 #include "js/CompilationAndEvaluation.h"
     26 #include "js/CompileOptions.h"         // JS::CompileOptions
     27 #include "js/ErrorReport.h"            // JS_ReportErrorUTF8, JSErrorReport
     28 #include "js/Exception.h"              // JS_ErrorFromException
     29 #include "js/friend/JSMEnvironment.h"  // JS::ExecuteInJSMEnvironment, JS::GetJSMEnvironmentOfScriptedCaller, JS::NewJSMEnvironment
     30 #include "js/friend/ErrorMessages.h"   // JSMSG_*
     31 #include "js/loader/ModuleLoadRequest.h"
     32 #include "js/Object.h"  // JS::GetCompartment
     33 #include "js/Printf.h"
     34 #include "js/PropertyAndElement.h"  // JS_DefineFunctions, JS_DefineProperty, JS_Enumerate, JS_GetElement, JS_GetProperty, JS_GetPropertyById, JS_HasOwnProperty, JS_HasOwnPropertyById, JS_SetProperty, JS_SetPropertyById
     35 #include "js/PropertySpec.h"
     36 #include "js/SourceText.h"  // JS::SourceText
     37 #include "nsCOMPtr.h"
     38 #include "nsDirectoryServiceDefs.h"
     39 #include "nsDirectoryServiceUtils.h"
     40 #include "nsIFile.h"
     41 #include "mozJSModuleLoader.h"
     42 #include "mozJSLoaderUtils.h"
     43 #include "nsIFileURL.h"
     44 #include "nsIJARURI.h"
     45 #include "nsIChannel.h"
     46 #include "nsIStreamListener.h"
     47 #include "nsNetUtil.h"
     48 #include "nsJSUtils.h"
     49 #include "xpcprivate.h"
     50 #include "xpcpublic.h"
     51 #include "nsContentUtils.h"
     52 #include "nsContentSecurityUtils.h"
     53 #include "nsXULAppAPI.h"
     54 #include "WrapperFactory.h"
     55 #include "JSServices.h"
     56 
     57 #include "mozilla/scache/StartupCache.h"
     58 #include "mozilla/scache/StartupCacheUtils.h"
     59 #include "mozilla/ClearOnShutdown.h"
     60 #include "mozilla/MacroForEach.h"
     61 #include "mozilla/Preferences.h"
     62 #include "mozilla/ProfilerLabels.h"
     63 #include "mozilla/ProfilerMarkers.h"
     64 #include "mozilla/ResultExtensions.h"
     65 #include "mozilla/ScriptPreloader.h"
     66 #include "mozilla/StaticPrefs_browser.h"
     67 #include "mozilla/Try.h"
     68 #include "mozilla/dom/AutoEntryScript.h"
     69 #include "mozilla/dom/ReferrerPolicyBinding.h"
     70 #include "mozilla/dom/ScriptSettings.h"
     71 #include "mozilla/dom/WorkerCommon.h"  // dom::GetWorkerPrivateFromContext
     72 #include "mozilla/dom/WorkerPrivate.h"  // dom::WorkerPrivate, dom::AutoSyncLoopHolder
     73 #include "mozilla/dom/WorkerRef.h"  // dom::StrongWorkerRef, dom::ThreadSafeWorkerRef
     74 #include "mozilla/dom/WorkerRunnable.h"  // dom::MainThreadStopSyncLoopRunnable
     75 
     76 using namespace mozilla;
     77 using namespace mozilla::scache;
     78 using namespace mozilla::loader;
     79 using namespace xpc;
     80 using namespace JS;
     81 
     82 #define JS_CACHE_PREFIX(aScopeType, aCompilationTarget) \
     83  "jsloader/" aScopeType "/" aCompilationTarget
     84 
     85 // MOZ_LOG=JSModuleLoader:5
     86 static LazyLogModule gJSCLLog("JSModuleLoader");
     87 
     88 #define LOG(args) MOZ_LOG(gJSCLLog, mozilla::LogLevel::Debug, args)
     89 
     90 static bool Dump(JSContext* cx, unsigned argc, Value* vp) {
     91  if (!nsJSUtils::DumpEnabled()) {
     92    return true;
     93  }
     94 
     95  CallArgs args = CallArgsFromVp(argc, vp);
     96 
     97  if (args.length() == 0) {
     98    return true;
     99  }
    100 
    101  RootedString str(cx, JS::ToString(cx, args[0]));
    102  if (!str) {
    103    return false;
    104  }
    105 
    106  JS::UniqueChars utf8str = JS_EncodeStringToUTF8(cx, str);
    107  if (!utf8str) {
    108    return false;
    109  }
    110 
    111  MOZ_LOG(nsContentUtils::DOMDumpLog(), mozilla::LogLevel::Debug,
    112          ("[SystemGlobal.Dump] %s", utf8str.get()));
    113 #ifdef ANDROID
    114  __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.get());
    115 #endif
    116 #ifdef XP_WIN
    117  if (IsDebuggerPresent()) {
    118    nsAutoJSString wstr;
    119    if (!wstr.init(cx, str)) {
    120      return false;
    121    }
    122    OutputDebugStringW(wstr.get());
    123  }
    124 #endif
    125  fputs(utf8str.get(), stdout);
    126  fflush(stdout);
    127  return true;
    128 }
    129 
    130 static bool Debug(JSContext* cx, unsigned argc, Value* vp) {
    131 #ifdef DEBUG
    132  return Dump(cx, argc, vp);
    133 #else
    134  return true;
    135 #endif
    136 }
    137 
    138 static const JSFunctionSpec gGlobalFun[] = {
    139    JS_FN("dump", Dump, 1, 0), JS_FN("debug", Debug, 1, 0),
    140    JS_FN("atob", Atob, 1, 0), JS_FN("btoa", Btoa, 1, 0), JS_FS_END};
    141 
    142 mozJSModuleLoader::mozJSModuleLoader()
    143    :
    144 #ifdef STARTUP_RECORDER_ENABLED
    145      mImportStacks(16),
    146 #endif
    147      mInitialized(false),
    148      mLoaderGlobal(dom::RootingCx()),
    149      mServicesObj(dom::RootingCx()) {
    150 }
    151 
    152 #define ENSURE_DEP(name)          \
    153  {                               \
    154    nsresult rv = Ensure##name(); \
    155    NS_ENSURE_SUCCESS(rv, rv);    \
    156  }
    157 #define ENSURE_DEPS(...) MOZ_FOR_EACH(ENSURE_DEP, (), (__VA_ARGS__));
    158 #define BEGIN_ENSURE(self, ...) \
    159  {                             \
    160    if (m##self) return NS_OK;  \
    161    ENSURE_DEPS(__VA_ARGS__);   \
    162  }
    163 
    164 class MOZ_STACK_CLASS ModuleLoaderInfo {
    165 public:
    166  explicit ModuleLoaderInfo(const nsACString& aLocation)
    167      : mLocation(&aLocation) {}
    168  explicit ModuleLoaderInfo(JS::loader::ModuleLoadRequest* aRequest)
    169      : mLocation(nullptr), mURI(aRequest->URI()) {}
    170 
    171  nsIIOService* IOService() {
    172    MOZ_ASSERT(mIOService);
    173    return mIOService;
    174  }
    175  nsresult EnsureIOService() {
    176    if (mIOService) {
    177      return NS_OK;
    178    }
    179    nsresult rv;
    180    mIOService = do_GetIOService(&rv);
    181    return rv;
    182  }
    183 
    184  nsIURI* URI() {
    185    MOZ_ASSERT(mURI);
    186    return mURI;
    187  }
    188  nsresult EnsureURI() {
    189    BEGIN_ENSURE(URI, IOService);
    190    MOZ_ASSERT(mLocation);
    191    return mIOService->NewURI(*mLocation, nullptr, nullptr,
    192                              getter_AddRefs(mURI));
    193  }
    194 
    195  nsIChannel* ScriptChannel() {
    196    MOZ_ASSERT(mScriptChannel);
    197    return mScriptChannel;
    198  }
    199  nsresult EnsureScriptChannel() {
    200    BEGIN_ENSURE(ScriptChannel, IOService, URI);
    201 
    202    return NS_NewChannel(
    203        getter_AddRefs(mScriptChannel), mURI,
    204        nsContentUtils::GetSystemPrincipal(),
    205        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
    206        nsIContentPolicy::TYPE_SCRIPT,
    207        /* aCookieJarSettings = */ nullptr,
    208        /* aPerformanceStorage = */ nullptr,
    209        /* aLoadGroup = */ nullptr, /* aCallbacks = */ nullptr,
    210        nsIRequest::LOAD_NORMAL, mIOService, /* aSandboxFlags = */ 0);
    211  }
    212 
    213  nsIURI* ResolvedURI() {
    214    MOZ_ASSERT(mResolvedURI);
    215    return mResolvedURI;
    216  }
    217  nsresult EnsureResolvedURI() {
    218    BEGIN_ENSURE(ResolvedURI, URI);
    219    return ResolveURI(mURI, getter_AddRefs(mResolvedURI));
    220  }
    221 
    222 private:
    223  const nsACString* mLocation;
    224  nsCOMPtr<nsIIOService> mIOService;
    225  nsCOMPtr<nsIURI> mURI;
    226  nsCOMPtr<nsIChannel> mScriptChannel;
    227  nsCOMPtr<nsIURI> mResolvedURI;
    228 };
    229 
    230 #undef BEGIN_ENSURE
    231 #undef ENSURE_DEPS
    232 #undef ENSURE_DEP
    233 
    234 mozJSModuleLoader::~mozJSModuleLoader() {
    235  MOZ_ASSERT(!mInitialized,
    236             "UnloadModules() was not explicitly called before cleaning up "
    237             "mozJSModuleLoader");
    238 
    239  if (mInitialized) {
    240    UnloadModules();
    241  }
    242 }
    243 
    244 StaticRefPtr<mozJSModuleLoader> mozJSModuleLoader::sSelf;
    245 StaticRefPtr<mozJSModuleLoader> mozJSModuleLoader::sDevToolsLoader;
    246 
    247 void mozJSModuleLoader::FindTargetObject(JSContext* aCx,
    248                                         MutableHandleObject aTargetObject) {
    249  aTargetObject.set(JS::GetJSMEnvironmentOfScriptedCaller(aCx));
    250 
    251  // The above could fail if the scripted caller is not a JSM (it could be a DOM
    252  // scope, for instance).
    253  //
    254  // If the target object was not in the JSM shared global, return the global
    255  // instead. This is needed when calling the subscript loader within a frame
    256  // script, since it the FrameScript NSVO will have been found.
    257  if (!aTargetObject ||
    258      !IsLoaderGlobal(JS::GetNonCCWObjectGlobal(aTargetObject))) {
    259    aTargetObject.set(JS::GetScriptedCallerGlobal(aCx));
    260 
    261    // Return nullptr if the scripted caller is in a different compartment.
    262    if (JS::GetCompartment(aTargetObject) != js::GetContextCompartment(aCx)) {
    263      aTargetObject.set(nullptr);
    264    }
    265  }
    266 }
    267 
    268 void mozJSModuleLoader::InitStatics() {
    269  MOZ_ASSERT(!sSelf);
    270  sSelf = new mozJSModuleLoader();
    271 
    272  dom::AutoJSAPI jsapi;
    273  jsapi.Init();
    274  JSContext* cx = jsapi.cx();
    275  sSelf->InitSharedGlobal(cx);
    276 
    277  NonSharedGlobalSyncModuleLoaderScope::InitStatics();
    278 }
    279 
    280 void mozJSModuleLoader::UnloadLoaders() {
    281  if (sSelf) {
    282    sSelf->Unload();
    283  }
    284  if (sDevToolsLoader) {
    285    sDevToolsLoader->Unload();
    286  }
    287 }
    288 
    289 void mozJSModuleLoader::Unload() {
    290  UnloadModules();
    291 
    292  if (mModuleLoader) {
    293    mModuleLoader->Shutdown();
    294    mModuleLoader = nullptr;
    295  }
    296 }
    297 
    298 void mozJSModuleLoader::ShutdownLoaders() {
    299  MOZ_ASSERT(sSelf);
    300  sSelf = nullptr;
    301 
    302  if (sDevToolsLoader) {
    303    sDevToolsLoader = nullptr;
    304  }
    305 }
    306 
    307 mozJSModuleLoader* mozJSModuleLoader::GetOrCreateDevToolsLoader(
    308    JSContext* aCx) {
    309  if (sDevToolsLoader) {
    310    return sDevToolsLoader;
    311  }
    312  sDevToolsLoader = new mozJSModuleLoader();
    313 
    314  sDevToolsLoader->InitSharedGlobal(aCx);
    315 
    316  return sDevToolsLoader;
    317 }
    318 
    319 void mozJSModuleLoader::InitSyncModuleLoaderForGlobal(
    320    nsIGlobalObject* aGlobal) {
    321  MOZ_ASSERT(!mLoaderGlobal);
    322  MOZ_ASSERT(!mModuleLoader);
    323 
    324  RefPtr<SyncScriptLoader> scriptLoader = new SyncScriptLoader;
    325  mModuleLoader = new SyncModuleLoader(scriptLoader, aGlobal);
    326  mLoaderGlobal = aGlobal->GetGlobalJSObject();
    327 }
    328 
    329 void mozJSModuleLoader::DisconnectSyncModuleLoaderFromGlobal() {
    330  MOZ_ASSERT(mLoaderGlobal);
    331  MOZ_ASSERT(mModuleLoader);
    332 
    333  mLoaderGlobal = nullptr;
    334  Unload();
    335 }
    336 
    337 /* static */
    338 bool mozJSModuleLoader::IsSharedSystemGlobal(nsIGlobalObject* aGlobal) {
    339  return sSelf->IsLoaderGlobal(aGlobal->GetGlobalJSObject());
    340 }
    341 
    342 /* static */
    343 bool mozJSModuleLoader::IsDevToolsLoaderGlobal(nsIGlobalObject* aGlobal) {
    344  return sDevToolsLoader &&
    345         sDevToolsLoader->IsLoaderGlobal(aGlobal->GetGlobalJSObject());
    346 }
    347 
    348 #ifdef STARTUP_RECORDER_ENABLED
    349 template <class Key, class Data, class UserData, class Converter>
    350 static size_t SizeOfStringTableExcludingThis(
    351    const nsBaseHashtable<Key, Data, UserData, Converter>& aTable,
    352    MallocSizeOf aMallocSizeOf) {
    353  size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
    354  for (const auto& entry : aTable) {
    355    n += entry.GetKey().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    356    n += entry.GetData().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
    357  }
    358  return n;
    359 }
    360 #endif
    361 
    362 size_t mozJSModuleLoader::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
    363  size_t n = aMallocSizeOf(this);
    364 #ifdef STARTUP_RECORDER_ENABLED
    365  n += SizeOfStringTableExcludingThis(mImportStacks, aMallocSizeOf);
    366 #endif
    367  return n;
    368 }
    369 
    370 void mozJSModuleLoader::CreateLoaderGlobal(JSContext* aCx,
    371                                           const nsACString& aLocation,
    372                                           MutableHandleObject aGlobal) {
    373  auto systemGlobal = MakeRefPtr<SystemGlobal>();
    374  RealmOptions options;
    375  auto& creationOptions = options.creationOptions();
    376 
    377  creationOptions.setFreezeBuiltins(true).setNewCompartmentInSystemZone();
    378  if (IsDevToolsLoader()) {
    379    creationOptions.setInvisibleToDebugger(true);
    380  }
    381  xpc::SetPrefableRealmOptions(options);
    382 
    383  // Defer firing OnNewGlobalObject until after the __URI__ property has
    384  // been defined so the JS debugger can tell what module the global is
    385  // for
    386  RootedObject global(aCx);
    387 
    388 #ifdef DEBUG
    389  // See mozJSModuleLoader::DefineJSServices.
    390  mIsInitializingLoaderGlobal = true;
    391 #endif
    392  nsresult rv = xpc::InitClassesWithNewWrappedGlobal(
    393      aCx, static_cast<nsIGlobalObject*>(systemGlobal),
    394      nsContentUtils::GetSystemPrincipal(), xpc::DONT_FIRE_ONNEWGLOBALHOOK,
    395      options, &global);
    396 #ifdef DEBUG
    397  mIsInitializingLoaderGlobal = false;
    398 #endif
    399  NS_ENSURE_SUCCESS_VOID(rv);
    400 
    401  NS_ENSURE_TRUE_VOID(global);
    402 
    403  systemGlobal->SetGlobalObject(global);
    404 
    405  JSAutoRealm ar(aCx, global);
    406  if (!JS_DefineFunctions(aCx, global, gGlobalFun)) {
    407    return;
    408  }
    409 
    410  if (!CreateJSServices(aCx)) {
    411    return;
    412  }
    413 
    414  if (!DefineJSServices(aCx, global)) {
    415    return;
    416  }
    417 
    418  // Set the location information for the new global, so that tools like
    419  // about:memory may use that information
    420  xpc::SetLocationForGlobal(global, aLocation);
    421 
    422  MOZ_ASSERT(!mModuleLoader);
    423  RefPtr<SyncScriptLoader> scriptLoader = new SyncScriptLoader;
    424  mModuleLoader = new SyncModuleLoader(scriptLoader, systemGlobal);
    425  systemGlobal->InitModuleLoader(mModuleLoader);
    426 
    427  aGlobal.set(global);
    428 }
    429 
    430 void mozJSModuleLoader::InitSharedGlobal(JSContext* aCx) {
    431  JS::RootedObject globalObj(aCx);
    432 
    433  CreateLoaderGlobal(
    434      aCx, IsDevToolsLoader() ? "DevTools global"_ns : "shared JSM global"_ns,
    435      &globalObj);
    436 
    437  // If we fail to create a module global this early, we're not going to
    438  // get very far, so just bail out now.
    439  MOZ_RELEASE_ASSERT(globalObj);
    440  mLoaderGlobal = globalObj;
    441 
    442  // AutoEntryScript required to invoke debugger hook, which is a
    443  // Gecko-specific concept at present.
    444  dom::AutoEntryScript aes(globalObj, "module loader report global");
    445  JS_FireOnNewGlobalObject(aes.cx(), globalObj);
    446 }
    447 
    448 // Read script file on the main thread and pass it back to worker.
    449 class ScriptReaderRunnable final : public nsIRunnable,
    450                                   public nsINamed,
    451                                   public nsIStreamListener {
    452 public:
    453  ScriptReaderRunnable(RefPtr<dom::ThreadSafeWorkerRef>&& aWorkerRef,
    454                       nsIEventTarget* aSyncLoopTarget,
    455                       const nsCString& aLocation)
    456      : mLocation(aLocation),
    457        mRv(NS_ERROR_FAILURE),
    458        mWorkerRef(std::move(aWorkerRef)),
    459        mSyncLoopTarget(aSyncLoopTarget) {}
    460 
    461  NS_DECL_THREADSAFE_ISUPPORTS
    462 
    463  nsCString& Data() { return mData; }
    464 
    465  nsresult Result() const { return mRv; }
    466 
    467  // nsIRunnable
    468 
    469  NS_IMETHOD
    470  Run() override {
    471    MOZ_ASSERT(NS_IsMainThread());
    472 
    473    nsresult rv = StartReadScriptFromLocation();
    474    if (NS_FAILED(rv)) {
    475      OnComplete(rv);
    476    }
    477 
    478    return NS_OK;
    479  }
    480 
    481  // nsINamed
    482 
    483  NS_IMETHOD
    484  GetName(nsACString& aName) override {
    485    aName.AssignLiteral("ScriptReaderRunnable");
    486    return NS_OK;
    487  }
    488 
    489  // nsIStreamListener
    490 
    491  NS_IMETHOD OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
    492                             uint64_t aOffset, uint32_t aCount) override {
    493    uint32_t read = 0;
    494    return aInputStream->ReadSegments(AppendSegmentToData, this, aCount, &read);
    495  }
    496 
    497  // nsIRequestObserver
    498 
    499  NS_IMETHOD OnStartRequest(nsIRequest* aRequest) override { return NS_OK; }
    500 
    501  NS_IMETHOD OnStopRequest(nsIRequest* aRequest,
    502                           nsresult aStatusCode) override {
    503    OnComplete(aStatusCode);
    504    return NS_OK;
    505  }
    506 
    507 private:
    508  ~ScriptReaderRunnable() = default;
    509 
    510  static nsresult AppendSegmentToData(nsIInputStream* aInputStream,
    511                                      void* aClosure, const char* aRawSegment,
    512                                      uint32_t aToOffset, uint32_t aCount,
    513                                      uint32_t* outWrittenCount) {
    514    auto* self = static_cast<ScriptReaderRunnable*>(aClosure);
    515    self->mData.Append(aRawSegment, aCount);
    516    *outWrittenCount = aCount;
    517    return NS_OK;
    518  }
    519 
    520  void OnComplete(nsresult aRv) {
    521    MOZ_ASSERT(NS_IsMainThread());
    522    MOZ_ASSERT(mWorkerRef);
    523 
    524    mRv = aRv;
    525 
    526    RefPtr<dom::MainThreadStopSyncLoopRunnable> runnable =
    527        new dom::MainThreadStopSyncLoopRunnable(std::move(mSyncLoopTarget),
    528                                                mRv);
    529    MOZ_ALWAYS_TRUE(runnable->Dispatch(mWorkerRef->Private()));
    530 
    531    mWorkerRef = nullptr;
    532    mSyncLoopTarget = nullptr;
    533  }
    534 
    535  nsresult StartReadScriptFromLocation() {
    536    MOZ_ASSERT(NS_IsMainThread());
    537 
    538    ModuleLoaderInfo info(mLocation);
    539    nsresult rv = info.EnsureScriptChannel();
    540    NS_ENSURE_SUCCESS(rv, rv);
    541 
    542    return info.ScriptChannel()->AsyncOpen(this);
    543  }
    544 
    545 private:
    546  nsAutoCString mLocation;
    547  nsCString mData;
    548  nsresult mRv;
    549 
    550  RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
    551 
    552  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
    553 };
    554 
    555 NS_IMPL_ISUPPORTS(ScriptReaderRunnable, nsIRunnable, nsINamed,
    556                  nsIStreamListener)
    557 
    558 /* static */
    559 nsresult mozJSModuleLoader::ReadScriptOnMainThread(JSContext* aCx,
    560                                                   const nsCString& aLocation,
    561                                                   nsCString& aData) {
    562  dom::WorkerPrivate* workerPrivate = dom::GetWorkerPrivateFromContext(aCx);
    563  MOZ_ASSERT(workerPrivate);
    564 
    565  dom::AutoSyncLoopHolder syncLoop(workerPrivate, dom::WorkerStatus::Canceling);
    566  nsCOMPtr<nsISerialEventTarget> syncLoopTarget =
    567      syncLoop.GetSerialEventTarget();
    568  if (!syncLoopTarget) {
    569    return NS_ERROR_DOM_INVALID_STATE_ERR;
    570  }
    571 
    572  RefPtr<dom::StrongWorkerRef> workerRef = dom::StrongWorkerRef::Create(
    573      workerPrivate, "mozJSModuleLoader::ScriptReaderRunnable", nullptr);
    574  if (!workerRef) {
    575    return NS_ERROR_DOM_INVALID_STATE_ERR;
    576  }
    577  RefPtr<dom::ThreadSafeWorkerRef> tsWorkerRef =
    578      MakeRefPtr<dom::ThreadSafeWorkerRef>(workerRef);
    579 
    580  RefPtr<ScriptReaderRunnable> runnable = new ScriptReaderRunnable(
    581      std::move(tsWorkerRef), syncLoopTarget, aLocation);
    582 
    583  if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
    584    return NS_ERROR_FAILURE;
    585  }
    586 
    587  syncLoop.Run();
    588 
    589  if (NS_FAILED(runnable->Result())) {
    590    return runnable->Result();
    591  }
    592 
    593  aData = std::move(runnable->Data());
    594 
    595  return NS_OK;
    596 }
    597 
    598 /* static */
    599 nsresult mozJSModuleLoader::LoadSingleModuleScriptOnWorker(
    600    SyncModuleLoader* aModuleLoader, JSContext* aCx,
    601    JS::loader::ModuleLoadRequest* aRequest, MutableHandleScript aScriptOut) {
    602  nsAutoCString location;
    603  nsresult rv = aRequest->URI()->GetSpec(location);
    604  NS_ENSURE_SUCCESS(rv, rv);
    605 
    606  nsCString data;
    607  rv = ReadScriptOnMainThread(aCx, location, data);
    608  NS_ENSURE_SUCCESS(rv, rv);
    609 
    610  CompileOptions options(aCx);
    611  // NOTE: ScriptPreloader::FillCompileOptionsForCachedStencil shouldn't be
    612  //       used here because the module is put into the worker global's
    613  //       module map, instead of the shared global's module map, where the
    614  //       worker module loader doesn't support lazy source.
    615  //       Accessing the source requires the synchronous communication with the
    616  //       main thread, and supporting it requires too much complexity compared
    617  //       to the benefit.
    618  options.setNoScriptRval(true);
    619  options.setFileAndLine(location.BeginReading(), 1);
    620  SetModuleOptions(options);
    621 
    622  // Worker global doesn't have the source hook.
    623  MOZ_ASSERT(!options.sourceIsLazy);
    624 
    625  JS::SourceText<mozilla::Utf8Unit> srcBuf;
    626  if (!srcBuf.init(aCx, data.get(), data.Length(),
    627                   JS::SourceOwnership::Borrowed)) {
    628    return NS_ERROR_FAILURE;
    629  }
    630 
    631  RefPtr<JS::Stencil> stencil =
    632      CompileModuleScriptToStencil(aCx, options, srcBuf);
    633  if (!stencil) {
    634    return NS_ERROR_FAILURE;
    635  }
    636 
    637  aScriptOut.set(InstantiateStencil(aCx, stencil));
    638 
    639  return NS_OK;
    640 }
    641 
    642 /* static */
    643 nsresult mozJSModuleLoader::LoadSingleModuleScript(
    644    SyncModuleLoader* aModuleLoader, JSContext* aCx,
    645    JS::loader::ModuleLoadRequest* aRequest, MutableHandleScript aScriptOut) {
    646  AUTO_PROFILER_MARKER_TEXT(
    647      "ChromeUtils.importESModule static import", JS,
    648      MarkerOptions(MarkerStack::Capture(),
    649                    MarkerInnerWindowIdFromJSContext(aCx)),
    650      nsContentUtils::TruncatedURLForDisplay(aRequest->URI()));
    651 
    652  if (!NS_IsMainThread()) {
    653    return LoadSingleModuleScriptOnWorker(aModuleLoader, aCx, aRequest,
    654                                          aScriptOut);
    655  }
    656 
    657  ModuleLoaderInfo info(aRequest);
    658  nsresult rv = info.EnsureResolvedURI();
    659  NS_ENSURE_SUCCESS(rv, rv);
    660 
    661  nsCOMPtr<nsIFile> sourceFile;
    662  rv = GetSourceFile(info.ResolvedURI(), getter_AddRefs(sourceFile));
    663  NS_ENSURE_SUCCESS(rv, rv);
    664 
    665  bool realFile = LocationIsRealFile(aRequest->URI());
    666 
    667  RootedScript script(aCx);
    668  rv = GetScriptForLocation(aCx, info, sourceFile, realFile, aScriptOut);
    669  NS_ENSURE_SUCCESS(rv, rv);
    670 
    671 #ifdef STARTUP_RECORDER_ENABLED
    672  if (aModuleLoader == sSelf->mModuleLoader) {
    673    sSelf->RecordImportStack(aCx, aRequest);
    674  } else if (sDevToolsLoader &&
    675             aModuleLoader == sDevToolsLoader->mModuleLoader) {
    676    sDevToolsLoader->RecordImportStack(aCx, aRequest);
    677  } else {
    678    // NOTE: Do not record import stack for non-shared globals, given the
    679    //       loader is associated with the global only while importing.
    680  }
    681 #endif
    682 
    683  return NS_OK;
    684 }
    685 
    686 /* static */
    687 nsresult mozJSModuleLoader::GetSourceFile(nsIURI* aResolvedURI,
    688                                          nsIFile** aSourceFileOut) {
    689  // Get the JAR if there is one.
    690  nsCOMPtr<nsIJARURI> jarURI;
    691  nsresult rv = NS_OK;
    692  jarURI = do_QueryInterface(aResolvedURI, &rv);
    693  nsCOMPtr<nsIFileURL> baseFileURL;
    694  if (NS_SUCCEEDED(rv)) {
    695    nsCOMPtr<nsIURI> baseURI;
    696    while (jarURI) {
    697      jarURI->GetJARFile(getter_AddRefs(baseURI));
    698      jarURI = do_QueryInterface(baseURI, &rv);
    699    }
    700    baseFileURL = do_QueryInterface(baseURI, &rv);
    701    NS_ENSURE_SUCCESS(rv, rv);
    702  } else {
    703    baseFileURL = do_QueryInterface(aResolvedURI, &rv);
    704    NS_ENSURE_SUCCESS(rv, rv);
    705  }
    706 
    707  return baseFileURL->GetFile(aSourceFileOut);
    708 }
    709 
    710 /* static */
    711 bool mozJSModuleLoader::LocationIsRealFile(nsIURI* aURI) {
    712  // We need to be extra careful checking for URIs pointing to files.
    713  // EnsureFile may not always get called, especially on resource URIs so we
    714  // need to call GetFile to make sure this is a valid file.
    715  nsresult rv = NS_OK;
    716  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aURI, &rv);
    717  nsCOMPtr<nsIFile> testFile;
    718  if (NS_SUCCEEDED(rv)) {
    719    fileURL->GetFile(getter_AddRefs(testFile));
    720  }
    721 
    722  return bool(testFile);
    723 }
    724 
    725 static mozilla::Result<nsCString, nsresult> ReadScript(
    726    ModuleLoaderInfo& aInfo) {
    727  MOZ_TRY(aInfo.EnsureScriptChannel());
    728 
    729  nsCOMPtr<nsIInputStream> scriptStream;
    730  MOZ_TRY(aInfo.ScriptChannel()->Open(getter_AddRefs(scriptStream)));
    731 
    732  uint64_t len64;
    733  uint32_t bytesRead;
    734 
    735  MOZ_TRY(scriptStream->Available(&len64));
    736  NS_ENSURE_TRUE(len64 < UINT32_MAX, Err(NS_ERROR_FILE_TOO_BIG));
    737  NS_ENSURE_TRUE(len64, Err(NS_ERROR_FAILURE));
    738  uint32_t len = (uint32_t)len64;
    739 
    740  /* malloc an internal buf the size of the file */
    741  nsCString str;
    742  if (!str.SetLength(len, fallible)) {
    743    return Err(NS_ERROR_OUT_OF_MEMORY);
    744  }
    745 
    746  /* read the file in one swoop */
    747  MOZ_TRY(scriptStream->Read(str.BeginWriting(), len, &bytesRead));
    748  if (bytesRead != len) {
    749    return Err(NS_BASE_STREAM_OSERROR);
    750  }
    751 
    752  return std::move(str);
    753 }
    754 
    755 /* static */
    756 void mozJSModuleLoader::SetModuleOptions(CompileOptions& aOptions) {
    757  aOptions.setModule();
    758 
    759  // Top level await is not supported in synchronously loaded modules.
    760  aOptions.topLevelAwait = false;
    761 }
    762 
    763 /* static */
    764 nsresult mozJSModuleLoader::GetScriptForLocation(
    765    JSContext* aCx, ModuleLoaderInfo& aInfo, nsIFile* aModuleFile,
    766    bool aUseMemMap, MutableHandleScript aScriptOut, char** aLocationOut) {
    767  // JS compilation errors are returned via an exception on the context.
    768  MOZ_ASSERT(!JS_IsExceptionPending(aCx));
    769 
    770  aScriptOut.set(nullptr);
    771 
    772  nsAutoCString nativePath;
    773  nsresult rv = aInfo.URI()->GetSpec(nativePath);
    774  NS_ENSURE_SUCCESS(rv, rv);
    775 
    776  // Before compiling the script, first check to see if we have it in
    777  // the preloader cache or the startupcache.  Note: as a rule, preloader cache
    778  // errors and startupcache errors are not fatal to loading the script, since
    779  // we can always slow-load.
    780 
    781  bool storeIntoStartupCache = false;
    782  StartupCache* cache = StartupCache::GetSingleton();
    783 
    784  aInfo.EnsureResolvedURI();
    785 
    786  nsAutoCString cachePath;
    787  rv = PathifyURI(JS_CACHE_PREFIX("non-syntactic", "module"),
    788                  aInfo.ResolvedURI(), cachePath);
    789  NS_ENSURE_SUCCESS(rv, rv);
    790 
    791  JS::DecodeOptions decodeOptions;
    792  ScriptPreloader::FillDecodeOptionsForCachedStencil(decodeOptions);
    793 
    794  RefPtr<JS::Stencil> stencil =
    795      ScriptPreloader::GetSingleton().GetCachedStencil(aCx, decodeOptions,
    796                                                       cachePath);
    797 
    798  if (!stencil && cache) {
    799    ReadCachedStencil(cache, cachePath, aCx, decodeOptions,
    800                      getter_AddRefs(stencil));
    801    if (!stencil) {
    802      JS_ClearPendingException(aCx);
    803 
    804      storeIntoStartupCache = true;
    805    }
    806  }
    807 
    808  if (stencil) {
    809    LOG(("Successfully loaded %s from cache\n", nativePath.get()));
    810  } else {
    811    // The script wasn't in the cache , so compile it now.
    812    LOG(("Slow loading %s\n", nativePath.get()));
    813 
    814    CompileOptions options(aCx);
    815    ScriptPreloader::FillCompileOptionsForCachedStencil(options);
    816    options.setFileAndLine(nativePath.get(), 1);
    817    SetModuleOptions(options);
    818 
    819    // If we can no longer write to caches, we should stop using lazy sources
    820    // and instead let normal syntax parsing occur. This can occur in content
    821    // processes after the ScriptPreloader is flushed where we can read but no
    822    // longer write.
    823    if (!storeIntoStartupCache && !ScriptPreloader::GetSingleton().Active()) {
    824      options.setSourceIsLazy(false);
    825    }
    826 
    827    if (aUseMemMap) {
    828      AutoMemMap map;
    829      MOZ_TRY(map.init(aModuleFile));
    830 
    831      // Note: exceptions will get handled further down;
    832      // don't early return for them here.
    833      auto buf = map.get<char>();
    834 
    835      JS::SourceText<mozilla::Utf8Unit> srcBuf;
    836      if (srcBuf.init(aCx, buf.get(), map.size(),
    837                      JS::SourceOwnership::Borrowed)) {
    838        stencil = CompileModuleScriptToStencil(aCx, options, srcBuf);
    839      }
    840    } else {
    841      nsCString str = MOZ_TRY(ReadScript(aInfo));
    842 
    843      JS::SourceText<mozilla::Utf8Unit> srcBuf;
    844      if (srcBuf.init(aCx, str.get(), str.Length(),
    845                      JS::SourceOwnership::Borrowed)) {
    846        stencil = CompileModuleScriptToStencil(aCx, options, srcBuf);
    847      }
    848    }
    849 
    850 #ifdef DEBUG
    851    // The above shouldn't touch any options for instantiation.
    852    JS::InstantiateOptions instantiateOptions(options);
    853    instantiateOptions.assertDefault();
    854 #endif
    855 
    856    if (!stencil) {
    857      return NS_ERROR_FAILURE;
    858    }
    859  }
    860 
    861  aScriptOut.set(InstantiateStencil(aCx, stencil));
    862  if (!aScriptOut) {
    863    return NS_ERROR_FAILURE;
    864  }
    865 
    866  // ScriptPreloader::NoteScript needs to be called unconditionally, to
    867  // reflect the usage into the next session's cache.
    868  ScriptPreloader::GetSingleton().NoteStencil(nativePath, cachePath, stencil);
    869 
    870  // Write to startup cache only when we didn't have any cache for the script
    871  // and compiled it.
    872  if (storeIntoStartupCache) {
    873    MOZ_ASSERT(stencil);
    874 
    875    // We successfully compiled the script, so cache it.
    876    rv = WriteCachedStencil(cache, cachePath, aCx, stencil);
    877 
    878    // Don't treat failure to write as fatal, since we might be working
    879    // with a read-only cache.
    880    if (NS_SUCCEEDED(rv)) {
    881      LOG(("Successfully wrote to cache\n"));
    882    } else {
    883      LOG(("Failed to write to cache\n"));
    884    }
    885  }
    886 
    887  /* Owned by ModuleEntry. Freed when we remove from the table. */
    888  if (aLocationOut) {
    889    *aLocationOut = ToNewCString(nativePath, mozilla::fallible);
    890    if (!*aLocationOut) {
    891      return NS_ERROR_OUT_OF_MEMORY;
    892    }
    893  }
    894 
    895  return NS_OK;
    896 }
    897 
    898 void mozJSModuleLoader::UnloadModules() {
    899  MOZ_ASSERT(!mIsUnloaded);
    900 
    901  mInitialized = false;
    902  mIsUnloaded = true;
    903 
    904  if (mLoaderGlobal) {
    905    MOZ_ASSERT(JS_HasExtensibleLexicalEnvironment(mLoaderGlobal));
    906    JS::RootedObject lexicalEnv(dom::RootingCx(),
    907                                JS_ExtensibleLexicalEnvironment(mLoaderGlobal));
    908    JS_SetAllNonReservedSlotsToUndefined(lexicalEnv);
    909    JS_SetAllNonReservedSlotsToUndefined(mLoaderGlobal);
    910    mLoaderGlobal = nullptr;
    911  }
    912  mServicesObj = nullptr;
    913 
    914 #ifdef STARTUP_RECORDER_ENABLED
    915  mImportStacks.Clear();
    916 #endif
    917 }
    918 
    919 /* static */
    920 JSScript* mozJSModuleLoader::InstantiateStencil(JSContext* aCx,
    921                                                JS::Stencil* aStencil) {
    922  JS::InstantiateOptions instantiateOptions;
    923 
    924  RootedObject module(aCx);
    925  module = JS::InstantiateModuleStencil(aCx, instantiateOptions, aStencil);
    926  if (!module) {
    927    return nullptr;
    928  }
    929 
    930  return JS::GetModuleScript(module);
    931 }
    932 
    933 nsresult mozJSModuleLoader::IsESModuleLoaded(const nsACString& aLocation,
    934                                             bool* retval) {
    935  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
    936 
    937  if (mIsUnloaded) {
    938    *retval = false;
    939    return NS_OK;
    940  }
    941 
    942  mInitialized = true;
    943  ModuleLoaderInfo info(aLocation);
    944 
    945  nsresult rv = info.EnsureURI();
    946  NS_ENSURE_SUCCESS(rv, rv);
    947 
    948  if (mModuleLoader->IsModuleFetched(
    949          JS::loader::ModuleMapKey(info.URI(), ModuleType::JavaScript))) {
    950    *retval = true;
    951    return NS_OK;
    952  }
    953 
    954  *retval = false;
    955  return NS_OK;
    956 }
    957 
    958 nsresult mozJSModuleLoader::GetLoadedESModules(
    959    nsTArray<nsCString>& aLoadedModules) {
    960  return mModuleLoader->GetFetchedModuleURLs(aLoadedModules);
    961 }
    962 
    963 #ifdef STARTUP_RECORDER_ENABLED
    964 void mozJSModuleLoader::RecordImportStack(
    965    JSContext* aCx, JS::loader::ModuleLoadRequest* aRequest) {
    966  if (!StaticPrefs::browser_startup_record()) {
    967    return;
    968  }
    969 
    970  nsAutoCString location;
    971  nsresult rv = aRequest->URI()->GetSpec(location);
    972  if (NS_FAILED(rv)) {
    973    return;
    974  }
    975 
    976  auto recordJSStackOnly = [&]() {
    977    mImportStacks.InsertOrUpdate(
    978        location, xpc_PrintJSStack(aCx, false, false, false).get());
    979  };
    980 
    981  if (aRequest->IsTopLevel()) {
    982    recordJSStackOnly();
    983    return;
    984  }
    985 
    986  nsAutoCString importerSpec;
    987  rv = aRequest->mReferrer->GetSpec(importerSpec);
    988  if (NS_FAILED(rv)) {
    989    recordJSStackOnly();
    990    return;
    991  }
    992 
    993  auto importerStack = mImportStacks.Lookup(importerSpec);
    994  if (!importerStack) {
    995    // The importer's stack is not collected, possibly due to OOM.
    996    recordJSStackOnly();
    997    return;
    998  }
    999 
   1000  nsAutoCString stack;
   1001 
   1002  stack += "* import [\"";
   1003  stack += importerSpec;
   1004  stack += "\"]\n";
   1005  stack += *importerStack;
   1006 
   1007  mImportStacks.InsertOrUpdate(location, stack);
   1008 }
   1009 #endif
   1010 
   1011 nsresult mozJSModuleLoader::GetModuleImportStack(const nsACString& aLocation,
   1012                                                 nsACString& retval) {
   1013 #ifdef STARTUP_RECORDER_ENABLED
   1014  MOZ_ASSERT(nsContentUtils::IsCallerChrome());
   1015 
   1016  // When querying the DevTools loader, it may not be initialized yet
   1017  if (!mInitialized) {
   1018    return NS_ERROR_FAILURE;
   1019  }
   1020 
   1021  auto str = mImportStacks.Lookup(aLocation);
   1022  if (!str) {
   1023    return NS_ERROR_FAILURE;
   1024  }
   1025 
   1026  retval = *str;
   1027  return NS_OK;
   1028 #else
   1029  return NS_ERROR_NOT_IMPLEMENTED;
   1030 #endif
   1031 }
   1032 
   1033 nsresult mozJSModuleLoader::ImportESModule(
   1034    JSContext* aCx, const nsACString& aLocation,
   1035    JS::MutableHandleObject aModuleNamespace) {
   1036  using namespace JS::loader;
   1037 
   1038  if (mIsUnloaded) {
   1039    JS_ReportErrorASCII(aCx, "Module loaded is already unloaded");
   1040    return NS_ERROR_FAILURE;
   1041  }
   1042 
   1043  mInitialized = true;
   1044 
   1045  // Called from ChromeUtils::ImportESModule.
   1046  nsCString str(aLocation);
   1047 
   1048  AUTO_PROFILER_MARKER_TEXT(
   1049      "ChromeUtils.importESModule", JS,
   1050      MarkerOptions(MarkerStack::Capture(),
   1051                    MarkerInnerWindowIdFromJSContext(aCx)),
   1052      Substring(aLocation, 0, std::min(size_t(128), aLocation.Length())));
   1053 
   1054  RootedObject globalObj(aCx, GetSharedGlobal());
   1055  MOZ_ASSERT(globalObj);
   1056  MOZ_ASSERT_IF(NS_IsMainThread(),
   1057                xpc::Scriptability::Get(globalObj).Allowed());
   1058 
   1059  // The module loader should be instantiated when fetching the shared global
   1060  MOZ_ASSERT(mModuleLoader);
   1061 
   1062  JSAutoRealm ar(aCx, globalObj);
   1063 
   1064  nsCOMPtr<nsIURI> uri;
   1065  nsresult rv = NS_NewURI(getter_AddRefs(uri), aLocation);
   1066  NS_ENSURE_SUCCESS(rv, rv);
   1067 
   1068  if (!nsContentSecurityUtils::IsTrustedScheme(uri)) {
   1069    JS_ReportErrorASCII(aCx,
   1070                        "System modules must be loaded from a trusted scheme");
   1071    return NS_ERROR_FAILURE;
   1072  }
   1073 
   1074  nsCOMPtr<nsIPrincipal> principal =
   1075      mModuleLoader->GetGlobalObject()->PrincipalOrNull();
   1076  MOZ_ASSERT(principal);
   1077 
   1078  RefPtr<ScriptFetchOptions> options = new ScriptFetchOptions(
   1079      CORS_NONE, /* aNonce = */ u""_ns, dom::RequestPriority::Auto,
   1080      ParserMetadata::NotParserInserted, principal);
   1081 
   1082  RefPtr<SyncLoadContext> context = new SyncLoadContext();
   1083 
   1084  RefPtr<ModuleLoadRequest> request = new ModuleLoadRequest(
   1085      JS::ModuleType::JavaScript, dom::SRIMetadata(),
   1086      /* aReferrer = */ nullptr, context, ModuleLoadRequest::Kind::TopLevel,
   1087      mModuleLoader, nullptr);
   1088 
   1089  request->NoCacheEntryFound(dom::ReferrerPolicy::No_referrer, options, uri);
   1090 
   1091  rv = request->StartModuleLoad();
   1092  if (NS_FAILED(rv)) {
   1093    mModuleLoader->MaybeReportLoadError(aCx);
   1094    return rv;
   1095  }
   1096 
   1097  rv = mModuleLoader->ProcessRequests();
   1098  if (NS_FAILED(rv)) {
   1099    mModuleLoader->MaybeReportLoadError(aCx);
   1100    return rv;
   1101  }
   1102 
   1103  MOZ_ASSERT(request->IsFinished());
   1104  if (!request->mModuleScript) {
   1105    mModuleLoader->MaybeReportLoadError(aCx);
   1106    return NS_ERROR_FAILURE;
   1107  }
   1108 
   1109  // All modules are loaded. MaybeReportLoadError isn't necessary from here.
   1110 
   1111  if (!request->mModuleScript->HasErrorToRethrow() &&
   1112      !request->InstantiateModuleGraph()) {
   1113    return NS_ERROR_FAILURE;
   1114  }
   1115 
   1116  rv = mModuleLoader->EvaluateModuleInContext(aCx, request,
   1117                                              JS::ThrowModuleErrorsSync);
   1118  NS_ENSURE_SUCCESS(rv, rv);
   1119  if (JS_IsExceptionPending(aCx)) {
   1120    return NS_ERROR_FAILURE;
   1121  }
   1122 
   1123  RefPtr<ModuleScript> moduleScript = request->mModuleScript;
   1124  JS::Rooted<JSObject*> module(aCx, moduleScript->ModuleRecord());
   1125  aModuleNamespace.set(JS::GetModuleNamespace(aCx, module));
   1126 
   1127  return NS_OK;
   1128 }
   1129 
   1130 bool mozJSModuleLoader::CreateJSServices(JSContext* aCx) {
   1131  JSObject* services = NewJSServices(aCx);
   1132  if (!services) {
   1133    return false;
   1134  }
   1135 
   1136  mServicesObj = services;
   1137  return true;
   1138 }
   1139 
   1140 bool mozJSModuleLoader::DefineJSServices(JSContext* aCx,
   1141                                         JS::Handle<JSObject*> aGlobal) {
   1142  if (!mServicesObj) {
   1143    // This function is called whenever creating a new global that needs
   1144    // `Services`, including the loader's shared global.
   1145    //
   1146    // This function is no-op if it's called during creating the loader's
   1147    // shared global.
   1148    //
   1149    // See also  CreateAndDefineJSServices.
   1150    MOZ_ASSERT(!mLoaderGlobal);
   1151    MOZ_ASSERT(mIsInitializingLoaderGlobal);
   1152    return true;
   1153  }
   1154 
   1155  JS::Rooted<JS::Value> services(aCx, ObjectValue(*mServicesObj));
   1156  if (!JS_WrapValue(aCx, &services)) {
   1157    return false;
   1158  }
   1159 
   1160  JS::Rooted<JS::PropertyKey> servicesId(
   1161      aCx, XPCJSContext::Get()->GetStringID(XPCJSContext::IDX_SERVICES));
   1162  return JS_DefinePropertyById(aCx, aGlobal, servicesId, services, 0);
   1163 }
   1164 
   1165 size_t mozJSModuleLoader::ModuleEntry::SizeOfIncludingThis(
   1166    MallocSizeOf aMallocSizeOf) const {
   1167  size_t n = aMallocSizeOf(this);
   1168  n += aMallocSizeOf(location);
   1169 
   1170  return n;
   1171 }
   1172 
   1173 //----------------------------------------------------------------------
   1174 
   1175 /* static */
   1176 MOZ_THREAD_LOCAL(mozJSModuleLoader*)
   1177 NonSharedGlobalSyncModuleLoaderScope::sTlsActiveLoader;
   1178 
   1179 void NonSharedGlobalSyncModuleLoaderScope::InitStatics() {
   1180  sTlsActiveLoader.infallibleInit();
   1181 }
   1182 
   1183 NonSharedGlobalSyncModuleLoaderScope::NonSharedGlobalSyncModuleLoaderScope(
   1184    JSContext* aCx, nsIGlobalObject* aGlobal) {
   1185  MOZ_ASSERT_IF(NS_IsMainThread(),
   1186                !mozJSModuleLoader::IsSharedSystemGlobal(aGlobal));
   1187  MOZ_ASSERT_IF(NS_IsMainThread(),
   1188                !mozJSModuleLoader::IsDevToolsLoaderGlobal(aGlobal));
   1189 
   1190  mAsyncModuleLoader = aGlobal->GetModuleLoader(aCx);
   1191  MOZ_ASSERT(mAsyncModuleLoader,
   1192             "The consumer should guarantee the global returns non-null module "
   1193             "loader");
   1194 
   1195  mLoader = new mozJSModuleLoader();
   1196  mLoader->InitSyncModuleLoaderForGlobal(aGlobal);
   1197 
   1198  mAsyncModuleLoader->CopyModulesTo(mLoader->mModuleLoader);
   1199 
   1200  mMaybeOverride.emplace(mAsyncModuleLoader, mLoader->mModuleLoader);
   1201 
   1202  MOZ_ASSERT(!sTlsActiveLoader.get());
   1203  sTlsActiveLoader.set(mLoader);
   1204 }
   1205 
   1206 NonSharedGlobalSyncModuleLoaderScope::~NonSharedGlobalSyncModuleLoaderScope() {
   1207  MOZ_ASSERT(sTlsActiveLoader.get() == mLoader);
   1208  sTlsActiveLoader.set(nullptr);
   1209 
   1210  mLoader->DisconnectSyncModuleLoaderFromGlobal();
   1211 }
   1212 
   1213 void NonSharedGlobalSyncModuleLoaderScope::Finish() {
   1214  mLoader->mModuleLoader->MoveModulesTo(mAsyncModuleLoader);
   1215 }
   1216 
   1217 /* static */
   1218 bool NonSharedGlobalSyncModuleLoaderScope::IsActive() {
   1219  return !!sTlsActiveLoader.get();
   1220 }
   1221 
   1222 /*static */
   1223 mozJSModuleLoader* NonSharedGlobalSyncModuleLoaderScope::ActiveLoader() {
   1224  return sTlsActiveLoader.get();
   1225 }