Bug 1481196 - Compile module scripts to a JSScript like we do for classic scripts r=jandem r=baku
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 08 Aug 2018 10:40:03 +0100
changeset 485703 ba122021b8b576cf33a17c148a2e6c73d1d32862
parent 485702 08d651dba0f60e2028ce7a4b891e809ffb7ff16b
child 485704 9e062ff4f63b7ac22be49b8a0861f191ebf9e901
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, baku
bugs1481196
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1481196 - Compile module scripts to a JSScript like we do for classic scripts r=jandem r=baku
dom/base/nsJSUtils.cpp
dom/base/nsJSUtils.h
dom/script/ModuleScript.cpp
dom/script/ModuleScript.h
dom/script/ScriptLoader.cpp
dom/script/ScriptLoader.h
js/public/Realm.h
js/src/builtin/ModuleObject.cpp
js/src/builtin/ModuleObject.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/jit/BaselineCompiler.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/shell/js.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/HelperThreads.h
js/src/vm/Interpreter.cpp
js/src/vm/Realm.cpp
js/src/vm/SelfHosting.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/src/xpcpublic.h
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -468,92 +468,91 @@ nsJSUtils::ExecutionContext::ExtractRetu
   return NS_OK;
 }
 
 nsresult
 nsJSUtils::CompileModule(JSContext* aCx,
                        JS::SourceBufferHolder& aSrcBuf,
                        JS::Handle<JSObject*> aEvaluationGlobal,
                        JS::CompileOptions &aCompileOptions,
-                       JS::MutableHandle<JSObject*> aModule)
+                       JS::MutableHandle<JSScript*> aScript)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(aSrcBuf.get());
   MOZ_ASSERT(JS_IsGlobalObject(aEvaluationGlobal));
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
   NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
 
-  if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
+  if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aScript)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
 nsJSUtils::InitModuleSourceElement(JSContext* aCx,
-                                   JS::Handle<JSObject*> aModule,
+                                   JS::Handle<JSScript*> aScript,
                                    nsIScriptElement* aElement)
 {
   JS::Rooted<JS::Value> value(aCx);
   nsresult rv = nsContentUtils::WrapNative(aCx, aElement, &value,
                                            /* aAllowWrapping = */ true);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   MOZ_ASSERT(value.isObject());
   JS::Rooted<JSObject*> object(aCx, &value.toObject());
 
-  JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aModule));
-  if (!JS::InitScriptSourceElement(aCx, script, object, nullptr)) {
+  if (!JS::InitScriptSourceElement(aCx, aScript, object, nullptr)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
+nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSScript*> aScript)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::ModuleInstantiate", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
-  NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aScript).Allowed(), NS_OK);
 
-  if (!JS::ModuleInstantiate(aCx, aModule)) {
+  if (!JS::ModuleInstantiate(aCx, aScript)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule)
+nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSScript*> aScript)
 {
   AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS);
 
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(CycleCollectedJSContext::Get() &&
              CycleCollectedJSContext::Get()->MicroTaskLevel());
 
-  NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
+  NS_ENSURE_TRUE(xpc::Scriptability::Get(aScript).Allowed(), NS_OK);
 
-  if (!JS::ModuleEvaluate(aCx, aModule)) {
+  if (!JS::ModuleEvaluate(aCx, aScript)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 static bool
 AddScopeChainItem(JSContext* aCx,
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -184,27 +184,27 @@ public:
                                  const uint8_t* aBuf, size_t aLength,
                                  JS::MutableHandle<JSScript*> aScript);
   };
 
   static nsresult CompileModule(JSContext* aCx,
                                 JS::SourceBufferHolder& aSrcBuf,
                                 JS::Handle<JSObject*> aEvaluationGlobal,
                                 JS::CompileOptions &aCompileOptions,
-                                JS::MutableHandle<JSObject*> aModule);
+                                JS::MutableHandle<JSScript*> aScript);
 
   static nsresult InitModuleSourceElement(JSContext* aCx,
-                                          JS::Handle<JSObject*> aModule,
+                                          JS::Handle<JSScript*> aScript,
                                           nsIScriptElement* aElement);
 
   static nsresult ModuleInstantiate(JSContext* aCx,
-                                    JS::Handle<JSObject*> aModule);
+                                    JS::Handle<JSScript*> aScript);
 
   static nsresult ModuleEvaluate(JSContext* aCx,
-                                 JS::Handle<JSObject*> aModule);
+                                 JS::Handle<JSScript*> aScript);
 
   // Returns false if an exception got thrown on aCx.  Passing a null
   // aElement is allowed; that wil produce an empty aScopeChain.
   static bool GetScopeChainForElement(JSContext* aCx,
                                       mozilla::dom::Element* aElement,
                                       JS::AutoObjectVector& aScopeChain);
 
   // Returns a scope chain suitable for XBL execution.
--- a/dom/script/ModuleScript.cpp
+++ b/dom/script/ModuleScript.cpp
@@ -16,108 +16,108 @@ namespace dom {
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
-  tmp->UnlinkModuleRecord();
+  tmp->UnlinkScript();
   tmp->mParseError.setUndefined();
   tmp->mErrorToRethrow.setUndefined();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScript)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
 
 ModuleScript::ModuleScript(ScriptLoader* aLoader, nsIURI* aBaseURL)
  : mLoader(aLoader),
    mBaseURL(aBaseURL),
    mSourceElementAssociated(false)
 {
   MOZ_ASSERT(mLoader);
   MOZ_ASSERT(mBaseURL);
-  MOZ_ASSERT(!mModuleRecord);
+  MOZ_ASSERT(!mScript);
   MOZ_ASSERT(!HasParseError());
   MOZ_ASSERT(!HasErrorToRethrow());
 }
 
 void
-ModuleScript::UnlinkModuleRecord()
+ModuleScript::UnlinkScript()
 {
   // Remove module's back reference to this object request if present.
-  if (mModuleRecord) {
-    MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
+  if (mScript) {
+    MOZ_ASSERT(JS::GetModuleHostDefinedField(mScript).toPrivate() ==
                this);
-    JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
-    mModuleRecord = nullptr;
+    JS::SetModuleHostDefinedField(mScript, JS::UndefinedValue());
+    mScript = nullptr;
   }
 }
 
 ModuleScript::~ModuleScript()
 {
   // The object may be destroyed without being unlinked first.
-  UnlinkModuleRecord();
+  UnlinkScript();
   DropJSObjects(this);
 }
 
 void
-ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
+ModuleScript::SetScript(JS::Handle<JSScript*> aScript)
 {
-  MOZ_ASSERT(!mModuleRecord);
+  MOZ_ASSERT(!mScript);
   MOZ_ASSERT(!HasParseError());
   MOZ_ASSERT(!HasErrorToRethrow());
 
-  mModuleRecord = aModuleRecord;
+  mScript = aScript;
 
   // Make module's host defined field point to this module script object.
-  // This is cleared in the UnlinkModuleRecord().
-  JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
+  // This is cleared in the UnlinkScript().
+  JS::SetModuleHostDefinedField(mScript, JS::PrivateValue(this));
   HoldJSObjects(this);
 }
 
 void
 ModuleScript::SetParseError(const JS::Value& aError)
 {
   MOZ_ASSERT(!aError.isUndefined());
   MOZ_ASSERT(!HasParseError());
   MOZ_ASSERT(!HasErrorToRethrow());
 
-  UnlinkModuleRecord();
+  UnlinkScript();
   mParseError = aError;
   HoldJSObjects(this);
 }
 
 void
 ModuleScript::SetErrorToRethrow(const JS::Value& aError)
 {
   MOZ_ASSERT(!aError.isUndefined());
   MOZ_ASSERT(!HasErrorToRethrow());
 
-  // This is only called after SetModuleRecord() or SetParseError() so we don't
+  // This is only called after SetScript() or SetParseError() so we don't
   // need to call HoldJSObjects() here.
-  MOZ_ASSERT(mModuleRecord || HasParseError());
+  MOZ_ASSERT(mScript || HasParseError());
 
   mErrorToRethrow = aError;
 }
 
 void
 ModuleScript::SetSourceElementAssociated()
 {
-  MOZ_ASSERT(mModuleRecord);
+  MOZ_ASSERT(mScript);
   MOZ_ASSERT(!mSourceElementAssociated);
 
   mSourceElementAssociated = true;
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/script/ModuleScript.h
+++ b/dom/script/ModuleScript.h
@@ -17,43 +17,43 @@ namespace mozilla {
 namespace dom {
 
 class ScriptLoader;
 
 class ModuleScript final : public nsISupports
 {
   RefPtr<ScriptLoader> mLoader;
   nsCOMPtr<nsIURI> mBaseURL;
-  JS::Heap<JSObject*> mModuleRecord;
+  JS::Heap<JSScript*> mScript;
   JS::Heap<JS::Value> mParseError;
   JS::Heap<JS::Value> mErrorToRethrow;
   bool mSourceElementAssociated;
 
   ~ModuleScript();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
 
   ModuleScript(ScriptLoader* aLoader,
                nsIURI* aBaseURL);
 
-  void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
+  void SetScript(JS::Handle<JSScript*> aScript);
   void SetParseError(const JS::Value& aError);
   void SetErrorToRethrow(const JS::Value& aError);
   void SetSourceElementAssociated();
 
   ScriptLoader* Loader() const { return mLoader; }
-  JSObject* ModuleRecord() const { return mModuleRecord; }
+  JSScript* Script() const { return mScript; }
   nsIURI* BaseURL() const { return mBaseURL; }
   JS::Value ParseError() const { return mParseError; }
   JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
   bool HasParseError() const { return !mParseError.isUndefined(); }
   bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
   bool SourceElementAssociated() const { return mSourceElementAssociated; }
 
-  void UnlinkModuleRecord();
+  void UnlinkScript();
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_ModuleScript_h
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -473,60 +473,60 @@ ScriptLoader::CreateModuleScript(ModuleL
   AutoEntryScript aes(globalObject, "CompileModule", true);
 
   bool oldProcessingScriptTag = context->GetProcessingScriptTag();
   context->SetProcessingScriptTag(true);
 
   nsresult rv;
   {
     JSContext* cx = aes.cx();
-    JS::Rooted<JSObject*> module(cx);
+    JS::Rooted<JSScript*> script(cx);
 
     if (aRequest->mWasCompiledOMT) {
-      module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
+      script = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
       aRequest->mOffThreadToken = nullptr;
-      rv = module ? NS_OK : NS_ERROR_FAILURE;
+      rv = script ? NS_OK : NS_ERROR_FAILURE;
     } else {
       JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
 
       JS::CompileOptions options(cx);
       rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
 
       if (NS_SUCCEEDED(rv)) {
         auto srcBuf = GetScriptSource(cx, aRequest);
         if (srcBuf) {
-          rv = nsJSUtils::CompileModule(cx, *srcBuf, global, options, &module);
+          rv = nsJSUtils::CompileModule(cx, *srcBuf, global, options, &script);
         } else {
           rv = NS_ERROR_OUT_OF_MEMORY;
         }
       }
     }
 
-    MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
+    MOZ_ASSERT(NS_SUCCEEDED(rv) == (script != nullptr));
 
     RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL);
     aRequest->mModuleScript = moduleScript;
 
-    if (!module) {
+    if (!script) {
       LOG(("ScriptLoadRequest (%p):   compilation failed (%d)",
            aRequest, unsigned(rv)));
 
       MOZ_ASSERT(aes.HasException());
       JS::Rooted<JS::Value> error(cx);
       if (!aes.StealException(&error)) {
         aRequest->mModuleScript = nullptr;
         return NS_ERROR_FAILURE;
       }
 
       moduleScript->SetParseError(error);
       aRequest->ModuleErrored();
       return NS_OK;
     }
 
-    moduleScript->SetModuleRecord(module);
+    moduleScript->SetScript(script);
 
     // Validate requested modules and treat failure to resolve module specifiers
     // the same as a parse error.
     rv = ResolveRequestedModules(aRequest, nullptr);
     if (NS_FAILED(rv)) {
       aRequest->ModuleErrored();
       return NS_OK;
     }
@@ -609,24 +609,24 @@ ResolveModuleSpecifier(ModuleScript* aSc
 }
 
 static nsresult
 ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOut)
 {
   ModuleScript* ms = aRequest->mModuleScript;
 
   AutoJSAPI jsapi;
-  if (!jsapi.Init(ms->ModuleRecord())) {
+  if (!jsapi.Init(JS::GetScriptGlobal(ms->Script()))) {
     return NS_ERROR_FAILURE;
   }
 
   JSContext* cx = jsapi.cx();
-  JS::Rooted<JSObject*> moduleRecord(cx, ms->ModuleRecord());
+  JS::Rooted<JSScript*> script(cx, ms->Script());
   JS::Rooted<JSObject*> requestedModules(cx);
-  requestedModules = JS::GetRequestedModules(cx, moduleRecord);
+  requestedModules = JS::GetRequestedModules(cx, script);
   MOZ_ASSERT(requestedModules);
 
   uint32_t length;
   if (!JS_GetArrayLength(cx, requestedModules, &length)) {
     return NS_ERROR_FAILURE;
   }
 
   JS::Rooted<JS::Value> element(cx);
@@ -750,24 +750,24 @@ ScriptLoader::StartFetchingModuleAndDepe
     childRequest->mReady.Reject(rv, __func__);
     return ready;
   }
 
   return ready;
 }
 
 // 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
-JSObject*
-HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
+JSScript*
+HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
                           JS::Handle<JSString*> aSpecifier)
 {
   // Let referencing module script be referencingModule.[[HostDefined]].
-  JS::Value value = JS::GetModuleHostDefinedField(aModule);
+  JS::Value value = JS::GetModuleHostDefinedField(aScript);
   auto script = static_cast<ModuleScript*>(value.toPrivate());
-  MOZ_ASSERT(script->ModuleRecord() == aModule);
+  MOZ_ASSERT(script->Script() == aScript);
 
   // Let url be the result of resolving a module specifier given referencing
   // module script and specifier.
   nsAutoJSString string;
   if (!string.init(aCx, aSpecifier)) {
     return nullptr;
   }
 
@@ -778,35 +778,35 @@ HostResolveImportedModule(JSContext* aCx
   MOZ_ASSERT(uri, "Failed to resolve previously-resolved module specifier");
 
   // Let resolved module script be moduleMap[url]. (This entry must exist for us
   // to have gotten to this point.)
   ModuleScript* ms = script->Loader()->GetFetchedModule(uri);
   MOZ_ASSERT(ms, "Resolved module not found in module map");
 
   MOZ_ASSERT(!ms->HasParseError());
-  MOZ_ASSERT(ms->ModuleRecord());
-
-  return ms->ModuleRecord();
+  MOZ_ASSERT(ms->Script());
+
+  return ms->Script();
 }
 
 bool
-HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSObject*> aModule,
+HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSScript*> aScript,
                        JS::Handle<JSObject*> aMetaObject)
 {
-  MOZ_DIAGNOSTIC_ASSERT(aModule);
-
-  JS::Value value = JS::GetModuleHostDefinedField(aModule);
+  MOZ_DIAGNOSTIC_ASSERT(aScript);
+
+  JS::Value value = JS::GetModuleHostDefinedField(aScript);
   if (value.isUndefined()) {
     JS_ReportErrorASCII(aCx, "Module script not found");
     return false;
   }
 
   auto script = static_cast<ModuleScript*>(value.toPrivate());
-  MOZ_DIAGNOSTIC_ASSERT(script->ModuleRecord() == aModule);
+  MOZ_DIAGNOSTIC_ASSERT(script->Script() == aScript);
 
   nsAutoCString url;
   MOZ_DIAGNOSTIC_ASSERT(script->BaseURL());
   MOZ_ALWAYS_SUCCEEDS(script->BaseURL()->GetAsciiSpec(url));
 
   JS::Rooted<JSString*> urlString(aCx, JS_NewStringCopyZ(aCx, url.get()));
   if (!urlString) {
     JS_ReportOutOfMemory(aCx);
@@ -927,28 +927,28 @@ ScriptLoader::InstantiateModuleTree(Modu
 
   JS::Value parseError = FindFirstParseError(aRequest);
   if (!parseError.isUndefined()) {
     moduleScript->SetErrorToRethrow(parseError);
     LOG(("ScriptLoadRequest (%p):   found parse error", aRequest));
     return true;
   }
 
-  MOZ_ASSERT(moduleScript->ModuleRecord());
+  MOZ_ASSERT(moduleScript->Script());
 
   nsAutoMicroTask mt;
   AutoJSAPI jsapi;
-  if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) {
+  if (NS_WARN_IF(!jsapi.Init(JS::GetScriptGlobal(moduleScript->Script())))) {
     return false;
   }
 
   EnsureModuleResolveHook(jsapi.cx());
 
-  JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
-  bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
+  JS::Rooted<JSScript*> script(jsapi.cx(), moduleScript->Script());
+  bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), script));
 
   if (!ok) {
     LOG(("ScriptLoadRequest (%p): Instantiate failed", aRequest));
     MOZ_ASSERT(jsapi.HasException());
     JS::RootedValue exception(jsapi.cx());
     if (!jsapi.StealException(&exception)) {
       return false;
     }
@@ -2298,30 +2298,29 @@ ScriptLoader::EvaluateScript(ScriptLoadR
       ModuleScript* moduleScript = request->mModuleScript;
       if (moduleScript->HasErrorToRethrow()) {
         LOG(("ScriptLoadRequest (%p):   module has error to rethrow", aRequest));
         JS::Rooted<JS::Value> error(cx, moduleScript->ErrorToRethrow());
         JS_SetPendingException(cx, error);
         return NS_OK; // An error is reported by AutoEntryScript.
       }
 
-      JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
-      MOZ_ASSERT(module);
+      JS::Rooted<JSScript*> script(cx, moduleScript->Script());
+      MOZ_ASSERT(script);
 
       if (!moduleScript->SourceElementAssociated()) {
-        rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->Element());
+        rv = nsJSUtils::InitModuleSourceElement(cx, script, aRequest->Element());
         NS_ENSURE_SUCCESS(rv, rv);
         moduleScript->SetSourceElementAssociated();
 
         // The script is now ready to be exposed to the debugger.
-        JS::Rooted<JSScript*> script(cx, JS::GetModuleScript(module));
         JS::ExposeScriptToDebugger(cx, script);
       }
 
-      rv = nsJSUtils::ModuleEvaluate(cx, module);
+      rv = nsJSUtils::ModuleEvaluate(cx, script);
       MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
       if (NS_FAILED(rv)) {
         LOG(("ScriptLoadRequest (%p):   evaluation failed", aRequest));
         rv = NS_OK; // An error is reported by AutoEntryScript.
       }
 
       aRequest->mCacheInfo = nullptr;
     } else {
--- a/dom/script/ScriptLoader.h
+++ b/dom/script/ScriptLoader.h
@@ -515,18 +515,18 @@ private:
                                                       nsresult aResult);
 
   bool IsFetchingModule(ModuleLoadRequest* aRequest) const;
 
   bool ModuleMapContainsURL(nsIURI* aURL) const;
   RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsIURI* aURL);
   ModuleScript* GetFetchedModule(nsIURI* aURL) const;
 
-  friend JSObject*
-  HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
+  friend JSScript*
+  HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
                           JS::Handle<JSString*> aSpecifier);
 
   // Returns wether we should save the bytecode of this script after the
   // execution of the script.
   static bool
   ShouldCacheBytecode(ScriptLoadRequest* aRequest);
 
   nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
--- a/js/public/Realm.h
+++ b/js/public/Realm.h
@@ -68,16 +68,21 @@ GetCompartmentForRealm(Realm* realm)
 }
 
 // Return an object's realm. All objects except cross-compartment wrappers are
 // created in a particular realm, which never changes. Returns null if obj is
 // a cross-compartment wrapper.
 extern JS_PUBLIC_API(Realm*)
 GetObjectRealmOrNull(JSObject* obj);
 
+// Return a script's realm. All scripts are created in a particular realm, which
+// never changes.
+extern JS_PUBLIC_API(Realm*)
+GetScriptRealm(JSScript* script);
+
 // Get the value of the "private data" internal field of the given Realm.
 // This field is initially null and is set using SetRealmPrivate.
 // It's a pointer to embeddding-specific data that SpiderMonkey never uses.
 extern JS_PUBLIC_API(void*)
 GetRealmPrivate(Realm* realm);
 
 // Set the "private data" internal field of the given Realm.
 extern JS_PUBLIC_API(void)
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1638,31 +1638,32 @@ ArrayObject* ModuleBuilder::createArray(
     uint32_t i = 0;
     for (auto r = map.all(); !r.empty(); r.popFront())
         array->initDenseElement(i++, ObjectValue(*r.front().value()));
 
     return array;
 }
 
 JSObject*
-js::GetOrCreateModuleMetaObject(JSContext* cx, HandleObject moduleArg)
+js::GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script)
 {
-    HandleModuleObject module = moduleArg.as<ModuleObject>();
+    MOZ_ASSERT(script->module());
+    RootedModuleObject module(cx, script->module());
     if (JSObject* obj = module->metaObject())
         return obj;
 
     RootedObject metaObject(cx, NewObjectWithGivenProto<PlainObject>(cx, nullptr));
     if (!metaObject)
         return nullptr;
 
     JS::ModuleMetadataHook func = cx->runtime()->moduleMetadataHook;
     if (!func) {
         JS_ReportErrorASCII(cx, "Module metadata hook not set");
         return nullptr;
     }
 
-    if (!func(cx, module, metaObject))
+    if (!func(cx, script, metaObject))
         return nullptr;
 
     module->setMetaObject(metaObject);
 
     return metaObject;
 }
--- a/js/src/builtin/ModuleObject.h
+++ b/js/src/builtin/ModuleObject.h
@@ -407,17 +407,17 @@ class MOZ_STACK_CLASS ModuleBuilder
 
     template <typename T>
     ArrayObject* createArray(const JS::Rooted<GCVector<T>>& vector);
     template <typename K, typename V>
     ArrayObject* createArray(const JS::Rooted<GCHashMap<K, V>>& map);
 };
 
 JSObject*
-GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
+GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script);
 
 } // namespace js
 
 template<>
 inline bool
 JSObject::is<js::ModuleNamespaceObject>() const
 {
     return js::IsDerivedProxyObject(this, &js::ModuleNamespaceObject::proxyHandler);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -42,17 +42,17 @@ class MOZ_STACK_CLASS BytecodeCompiler
     BytecodeCompiler(JSContext* cx,
                      LifoAlloc& alloc,
                      const ReadOnlyCompileOptions& options,
                      SourceBufferHolder& sourceBuffer,
                      HandleScope enclosingScope);
 
     JSScript* compileGlobalScript(ScopeKind scopeKind);
     JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
-    ModuleObject* compileModule();
+    JSScript* compileModule();
     bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
                                    FunctionAsyncKind asyncKind,
                                    const Maybe<uint32_t>& parameterListEnd);
 
     ScriptSourceObject* sourceObjectPtr() const;
 
   private:
     JSScript* compileScript(HandleObject environment, SharedContext* sc);
@@ -389,17 +389,17 @@ BytecodeCompiler::compileGlobalScript(Sc
 JSScript*
 BytecodeCompiler::compileEvalScript(HandleObject environment, HandleScope enclosingScope)
 {
     EvalSharedContext evalsc(cx, environment, enclosingScope,
                              directives, options.extraWarningsOption);
     return compileScript(environment, &evalsc);
 }
 
-ModuleObject*
+JSScript*
 BytecodeCompiler::compileModule()
 {
     if (!createSourceAndParser(ParseGoal::Module))
         return nullptr;
 
     Rooted<ModuleObject*> module(cx, ModuleObject::create(cx));
     if (!module)
         return nullptr;
@@ -433,17 +433,17 @@ BytecodeCompiler::compileModule()
 
     module->setInitialEnvironment(env);
 
     // Enqueue an off-thread source compression task after finishing parsing.
     if (!scriptSource->tryCompressOffThread(cx))
         return nullptr;
 
     MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
-    return module;
+    return script;
 }
 
 // Compile a standalone JS function, which might appear as the value of an
 // event handler attribute in an HTML <INPUT> tag, or in a Function()
 // constructor.
 bool
 BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
                                             GeneratorKind generatorKind,
@@ -682,17 +682,17 @@ frontend::CompileEvalScript(JSContext* c
     JSScript* script = compiler.compileEvalScript(environment, enclosingScope);
     if (!script)
         return nullptr;
     assertException.reset();
     return script;
 
 }
 
-ModuleObject*
+JSScript*
 frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInput,
                         SourceBufferHolder& srcBuf, LifoAlloc& alloc,
                         ScriptSourceObject** sourceObjectOut)
 {
     MOZ_ASSERT(srcBuf.get());
     MOZ_ASSERT_IF(sourceObjectOut, *sourceObjectOut == nullptr);
 
     AutoAssertReportedException assertException(cx);
@@ -700,45 +700,46 @@ frontend::CompileModule(JSContext* cx, c
     CompileOptions options(cx, optionsInput);
     options.maybeMakeStrictMode(true); // ES6 10.2.1 Module code is always strict mode code.
     options.setIsRunOnce(true);
     options.allowHTMLComments = false;
 
     RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
     BytecodeCompiler compiler(cx, alloc, options, srcBuf, emptyGlobalScope);
     AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
-    ModuleObject* module = compiler.compileModule();
-    if (!module)
+    JSScript* script = compiler.compileModule();
+    if (!script)
         return nullptr;
 
     assertException.reset();
-    return module;
+    return script;
 }
 
-ModuleObject*
+JSScript*
 frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                         SourceBufferHolder& srcBuf)
 {
     AutoAssertReportedException assertException(cx);
 
     if (!GlobalObject::ensureModulePrototypesCreated(cx, cx->global()))
         return nullptr;
 
     LifoAlloc& alloc = cx->tempLifoAlloc();
-    RootedModuleObject module(cx, CompileModule(cx, options, srcBuf, alloc));
-    if (!module)
+    RootedScript script(cx, CompileModule(cx, options, srcBuf, alloc));
+    if (!script)
         return nullptr;
 
     // This happens in GlobalHelperThreadState::finishModuleParseTask() when a
     // module is compiled off thread.
+    RootedModuleObject module(cx, script->module());
     if (!ModuleObject::Freeze(cx, module))
         return nullptr;
 
     assertException.reset();
-    return module;
+    return script;
 }
 
 // When leaving this scope, the given function should either:
 //   * be linked to a fully compiled script
 //   * remain linking to a lazy script
 class MOZ_STACK_CLASS AutoAssertFunctionDelazificationCompletion
 {
 #ifdef DEBUG
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -16,17 +16,16 @@
 #include "vm/TraceLogging.h"
 
 class JSLinearString;
 
 namespace js {
 
 class LazyScript;
 class LifoAlloc;
-class ModuleObject;
 class ScriptSourceObject;
 
 namespace frontend {
 
 class ErrorReporter;
 class FunctionBox;
 class ParseNode;
 
@@ -48,21 +47,21 @@ CompileGlobalBinASTScript(JSContext *cx,
 
 JSScript*
 CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
                   HandleObject scopeChain, HandleScope enclosingScope,
                   const ReadOnlyCompileOptions& options,
                   SourceBufferHolder& srcBuf,
                   ScriptSourceObject** sourceObjectOut = nullptr);
 
-ModuleObject*
+JSScript*
 CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
               SourceBufferHolder& srcBuf);
 
-ModuleObject*
+JSScript*
 CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
               SourceBufferHolder& srcBuf, LifoAlloc& alloc,
               ScriptSourceObject** sourceObjectOut = nullptr);
 
 MOZ_MUST_USE bool
 CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
 
 //
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -5133,15 +5133,16 @@ BaselineCompiler::emit_JSOP_DERIVEDCONST
 }
 
 bool
 BaselineCompiler::emit_JSOP_IMPORTMETA()
 {
     RootedModuleObject module(cx, GetModuleObjectForScript(script));
     MOZ_ASSERT(module);
 
-    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, module);
+    RootedScript moduleScript(cx, module->script());
+    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, moduleScript);
     if (!metaObject)
         return false;
 
     frame.push(ObjectValue(*metaObject));
     return true;
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1266,16 +1266,25 @@ JS::CurrentGlobalOrNull(JSContext* cx)
 JS_PUBLIC_API(JSObject*)
 JS::GetNonCCWObjectGlobal(JSObject* obj)
 {
     AssertHeapIsIdleOrIterating();
     MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj));
     return &obj->nonCCWGlobal();
 }
 
+JS_PUBLIC_API(JSObject*)
+JS::GetScriptGlobal(JSScript* script)
+{
+    AssertHeapIsIdleOrIterating();
+    JSObject* global = script->realm()->maybeGlobal();
+    MOZ_ASSERT(global);
+    return global;
+}
+
 JS_PUBLIC_API(bool)
 JS::detail::ComputeThis(JSContext* cx, Value* vp, MutableHandleObject thisObject)
 {
     AssertHeapIsIdle();
     assertSameCompartment(cx, vp[0], vp[1]);
 
     MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]);
     if (!BoxNonStrictThis(cx, thisv, thisv))
@@ -4242,17 +4251,17 @@ JS_PUBLIC_API(bool)
 JS::CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                            JS::SourceBufferHolder& srcBuf,
                            OffThreadCompileCallback callback, void* callbackData)
 {
     MOZ_ASSERT(CanCompileOffThread(cx, options, srcBuf.length()));
     return StartOffThreadParseModule(cx, options, srcBuf, callback, callbackData);
 }
 
-JS_PUBLIC_API(JSObject*)
+JS_PUBLIC_API(JSScript*)
 JS::FinishOffThreadModule(JSContext* cx, JS::OffThreadToken* token)
 {
     MOZ_ASSERT(cx);
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
     return HelperThreadState().finishModuleParseTask(cx, token);
 }
 
 JS_PUBLIC_API(void)
@@ -4833,63 +4842,71 @@ JS_PUBLIC_API(void)
 JS::SetModuleMetadataHook(JSRuntime* rt, JS::ModuleMetadataHook func)
 {
     AssertHeapIsIdle();
     rt->moduleMetadataHook = func;
 }
 
 JS_PUBLIC_API(bool)
 JS::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
-                  SourceBufferHolder& srcBuf, JS::MutableHandleObject module)
+                  SourceBufferHolder& srcBuf, JS::MutableHandleScript script)
 {
     MOZ_ASSERT(!cx->zone()->isAtomsZone());
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
 
-    module.set(frontend::CompileModule(cx, options, srcBuf));
-    return !!module;
+    script.set(frontend::CompileModule(cx, options, srcBuf));
+    return !!script;
 }
 
 JS_PUBLIC_API(void)
-JS::SetModuleHostDefinedField(JSObject* module, const JS::Value& value)
-{
-    module->as<ModuleObject>().setHostDefinedField(value);
+JS::SetModuleHostDefinedField(JSScript* script, const JS::Value& value)
+{
+    MOZ_ASSERT(script->module());
+    script->module()->setHostDefinedField(value);
 }
 
 JS_PUBLIC_API(JS::Value)
-JS::GetModuleHostDefinedField(JSObject* module)
-{
-    return module->as<ModuleObject>().hostDefinedField();
-}
-
-JS_PUBLIC_API(bool)
-JS::ModuleInstantiate(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return ModuleObject::Instantiate(cx, moduleArg.as<ModuleObject>());
-}
-
-JS_PUBLIC_API(bool)
-JS::ModuleEvaluate(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return ModuleObject::Evaluate(cx, moduleArg.as<ModuleObject>());
+JS::GetModuleHostDefinedField(JSScript* script)
+{
+    MOZ_ASSERT(script->module());
+    return script->module()->hostDefinedField();
+}
+
+JS_PUBLIC_API(bool)
+JS::ModuleInstantiate(JSContext* cx, JS::HandleScript script)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, script);
+    RootedModuleObject module(cx, script->module());
+    MOZ_ASSERT(module);
+    return ModuleObject::Instantiate(cx, module);
+}
+
+JS_PUBLIC_API(bool)
+JS::ModuleEvaluate(JSContext* cx, JS::HandleScript script)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, script);
+    RootedModuleObject module(cx, script->module());
+    MOZ_ASSERT(module);
+    return ModuleObject::Evaluate(cx, module);
 }
 
 JS_PUBLIC_API(JSObject*)
-JS::GetRequestedModules(JSContext* cx, JS::HandleObject moduleArg)
-{
-    AssertHeapIsIdle();
-    CHECK_REQUEST(cx);
-    assertSameCompartment(cx, moduleArg);
-    return &moduleArg->as<ModuleObject>().requestedModules();
+JS::GetRequestedModules(JSContext* cx, JS::HandleScript script)
+{
+    AssertHeapIsIdle();
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, script);
+    RootedModuleObject module(cx, script->module());
+    MOZ_ASSERT(module);
+    return &module->requestedModules();
 }
 
 JS_PUBLIC_API(JSString*)
 JS::GetRequestedModuleSpecifier(JSContext* cx, JS::HandleValue value)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, value);
@@ -4906,23 +4923,16 @@ JS::GetRequestedModuleSourcePos(JSContex
     assertSameCompartment(cx, value);
     MOZ_ASSERT(lineNumber);
     MOZ_ASSERT(columnNumber);
     auto& requested = value.toObject().as<RequestedModuleObject>();
     *lineNumber = requested.lineNumber();
     *columnNumber = requested.columnNumber();
 }
 
-JS_PUBLIC_API(JSScript*)
-JS::GetModuleScript(JS::HandleObject moduleRecord)
-{
-    AssertHeapIsIdle();
-    return moduleRecord->as<ModuleObject>().script();
-}
-
 JS_PUBLIC_API(JSObject*)
 JS_New(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, ctor, inputArgs);
 
     RootedValue ctorVal(cx, ObjectValue(*ctor));
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1229,16 +1229,22 @@ CurrentGlobalOrNull(JSContext* cx);
 /**
  * Get the global object associated with an object's realm. The object must not
  * be a cross-compartment wrapper (because CCWs are shared by all realms in the
  * compartment).
  */
 extern JS_PUBLIC_API(JSObject*)
 GetNonCCWObjectGlobal(JSObject* obj);
 
+/**
+ * Get the global object associated with a script's realm.
+ */
+extern JS_PUBLIC_API(JSObject*)
+GetScriptGlobal(JSScript* script);
+
 } // namespace JS
 
 /**
  * Add 'Reflect.parse', a SpiderMonkey extension, to the Reflect object on the
  * given global.
  */
 extern JS_PUBLIC_API(bool)
 JS_InitReflectParse(JSContext* cx, JS::HandleObject global);
@@ -3687,17 +3693,17 @@ FinishOffThreadScript(JSContext* cx, Off
 extern JS_PUBLIC_API(void)
 CancelOffThreadScript(JSContext* cx, OffThreadToken* token);
 
 extern JS_PUBLIC_API(bool)
 CompileOffThreadModule(JSContext* cx, const ReadOnlyCompileOptions& options,
                        JS::SourceBufferHolder& srcBuf,
                        OffThreadCompileCallback callback, void* callbackData);
 
-extern JS_PUBLIC_API(JSObject*)
+extern JS_PUBLIC_API(JSScript*)
 FinishOffThreadModule(JSContext* cx, OffThreadToken* token);
 
 extern JS_PUBLIC_API(void)
 CancelOffThreadModule(JSContext* cx, OffThreadToken* token);
 
 extern JS_PUBLIC_API(bool)
 DecodeOffThreadScript(JSContext* cx, const ReadOnlyCompileOptions& options,
                       mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
@@ -3859,88 +3865,88 @@ Evaluate(JSContext* cx, const ReadOnlyCo
 
 /**
  * Evaluate the given file in the scope of the current global of cx.
  */
 extern JS_PUBLIC_API(bool)
 Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
          const char* filename, JS::MutableHandleValue rval);
 
-using ModuleResolveHook = JSObject* (*)(JSContext*, HandleObject, HandleString);
+using ModuleResolveHook = JSScript* (*)(JSContext*, HandleScript, HandleString);
 
 /**
  * Get the HostResolveImportedModule hook for the runtime.
  */
 extern JS_PUBLIC_API(ModuleResolveHook)
 GetModuleResolveHook(JSRuntime* rt);
 
 /**
  * Set the HostResolveImportedModule hook for the runtime to the given function.
  */
 extern JS_PUBLIC_API(void)
 SetModuleResolveHook(JSRuntime* rt, ModuleResolveHook func);
 
-using ModuleMetadataHook = bool (*)(JSContext*, HandleObject, HandleObject);
+using ModuleMetadataHook = bool (*)(JSContext*, HandleScript, HandleObject);
 
 /**
  * Get the hook for populating the import.meta metadata object.
  */
 extern JS_PUBLIC_API(ModuleMetadataHook)
 GetModuleMetadataHook(JSRuntime* rt);
 
 /**
  * Set the hook for populating the import.meta metadata object to the given
  * function.
  */
 extern JS_PUBLIC_API(void)
 SetModuleMetadataHook(JSRuntime* rt, ModuleMetadataHook func);
 
 /**
  * Parse the given source buffer as a module in the scope of the current global
- * of cx and return a source text module record.
+ * of cx.
  */
 extern JS_PUBLIC_API(bool)
 CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
-              SourceBufferHolder& srcBuf, JS::MutableHandleObject moduleRecord);
+              SourceBufferHolder& srcBuf, JS::MutableHandleScript script);
 
 /**
  * Set the [[HostDefined]] field of a source text module record to the given
  * value.
  */
 extern JS_PUBLIC_API(void)
-SetModuleHostDefinedField(JSObject* module, const JS::Value& value);
+SetModuleHostDefinedField(JSScript* module, const JS::Value& value);
 
 /**
  * Get the [[HostDefined]] field of a source text module record.
  */
 extern JS_PUBLIC_API(JS::Value)
-GetModuleHostDefinedField(JSObject* module);
+GetModuleHostDefinedField(JSScript* script);
 
 /*
  * Perform the ModuleInstantiate operation on the given source text module
  * record.
  *
  * This transitively resolves all module dependencies (calling the
  * HostResolveImportedModule hook) and initializes the environment record for
  * the module.
  */
 extern JS_PUBLIC_API(bool)
-ModuleInstantiate(JSContext* cx, JS::HandleObject moduleRecord);
+ModuleInstantiate(JSContext* cx, JS::HandleScript script);
 
 /*
  * Perform the ModuleEvaluate operation on the given source text module record.
  *
  * This does nothing if this module has already been evaluated. Otherwise, it
  * transitively evaluates all dependences of this module and then evaluates this
  * module.
  *
  * ModuleInstantiate must have completed prior to calling this.
  */
 extern JS_PUBLIC_API(bool)
-ModuleEvaluate(JSContext* cx, JS::HandleObject moduleRecord);
+ModuleEvaluate(JSContext* cx, JS::HandleScript script);
 
 /*
  * Get a list of the module specifiers used by a source text module
  * record to request importation of modules.
  *
  * The result is a JavaScript array of object values.  To extract the individual
  * values use only JS_GetArrayLength and JS_GetElement with indices 0 to length
  * - 1.
@@ -3949,28 +3955,25 @@ ModuleEvaluate(JSContext* cx, JS::Handle
  *  - moduleSpecifier: the module specifier string
  *  - lineNumber: the line number of the import in the source text
  *  - columnNumber: the column number of the import in the source text
  *
  * These property values can be extracted with GetRequestedModuleSpecifier() and
  * GetRequestedModuleSourcePos()
  */
 extern JS_PUBLIC_API(JSObject*)
-GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord);
+GetRequestedModules(JSContext* cx, JS::HandleScript script);
 
 extern JS_PUBLIC_API(JSString*)
 GetRequestedModuleSpecifier(JSContext* cx, JS::HandleValue requestedModuleObject);
 
 extern JS_PUBLIC_API(void)
 GetRequestedModuleSourcePos(JSContext* cx, JS::HandleValue requestedModuleObject,
                             uint32_t* lineNumber, uint32_t* columnNumber);
 
-extern JS_PUBLIC_API(JSScript*)
-GetModuleScript(JS::HandleObject moduleRecord);
-
 } /* namespace JS */
 
 #if defined(JS_BUILD_BINAST)
 
 namespace JS {
 
 extern JS_PUBLIC_API(JSScript*)
 DecodeBinAST(JSContext* cx, const ReadOnlyCompileOptions& options,
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4294,21 +4294,21 @@ ParseModule(JSContext* cx, unsigned argc
     AutoStableStringChars stableChars(cx);
     if (!stableChars.initTwoByte(cx, scriptContents))
         return false;
 
     const char16_t* chars = stableChars.twoByteRange().begin().get();
     SourceBufferHolder srcBuf(chars, scriptContents->length(),
                               SourceBufferHolder::NoOwnership);
 
-    RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf));
-    if (!module)
-        return false;
-
-    args.rval().setObject(*module);
+    RootedScript script(cx, frontend::CompileModule(cx, options, srcBuf));
+    if (!script)
+        return false;
+
+    args.rval().setObject(*script->module());
     return true;
 }
 
 static bool
 SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
@@ -4325,48 +4325,49 @@ SetModuleResolveHook(JSContext* cx, unsi
 
     Handle<GlobalObject*> global = cx->global();
     global->setReservedSlot(GlobalAppSlotModuleResolveHook, args[0]);
 
     args.rval().setUndefined();
     return true;
 }
 
-static JSObject*
-CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier)
-{
+static JSScript*
+CallModuleResolveHook(JSContext* cx, HandleScript script, HandleString specifier)
+{
+    MOZ_ASSERT(script->module());
+
     Handle<GlobalObject*> global = cx->global();
     RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleResolveHook));
     if (hookValue.isUndefined()) {
         JS_ReportErrorASCII(cx, "Module resolve hook not set");
         return nullptr;
     }
     MOZ_ASSERT(hookValue.toObject().is<JSFunction>());
 
     JS::AutoValueArray<2> args(cx);
-    args[0].setObject(*module);
+    args[0].setObject(*script->module());
     args[1].setString(specifier);
 
     RootedValue result(cx);
     if (!JS_CallFunctionValue(cx, nullptr, hookValue, args, &result))
         return nullptr;
 
     if (!result.isObject() || !result.toObject().is<ModuleObject>()) {
          JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
          return nullptr;
     }
 
-    return &result.toObject();
-}
-
-static bool
-ShellModuleMetadataHook(JSContext* cx, HandleObject module, HandleObject metaObject)
+    return result.toObject().as<ModuleObject>().script();
+}
+
+static bool
+ShellModuleMetadataHook(JSContext* cx, HandleScript script, HandleObject metaObject)
 {
     // For the shell, just use the script's filename as the base URL.
-    RootedScript script(cx, module->as<ModuleObject>().script());
     const char* filename = script->scriptSource()->filename();
     MOZ_ASSERT(filename);
 
     RootedString url(cx, NewStringCopyZ<CanGC>(cx, filename));
     if (!url)
         return false;
 
     if (!JS_DefineProperty(cx, metaObject, "url", url, JSPROP_ENUMERATE))
@@ -4858,21 +4859,21 @@ FinishOffThreadModule(JSContext* cx, uns
     if (!job)
         return false;
 
     JS::OffThreadToken* token = job->waitUntilDone(cx);
     MOZ_ASSERT(token);
 
     DeleteOffThreadJob(cx, job);
 
-    RootedObject module(cx, JS::FinishOffThreadModule(cx, token));
-    if (!module)
-        return false;
-
-    args.rval().setObject(*module);
+    RootedScript script(cx, JS::FinishOffThreadModule(cx, token));
+    if (!script)
+        return false;
+
+    args.rval().setObject(*script->module());
     return true;
 }
 
 static bool
 OffThreadDecodeScript(JSContext* cx, unsigned argc, Value* vp)
 {
     if (!CanUseExtraThreads()) {
         JS_ReportErrorASCII(cx, "Can't use offThreadDecodeScript with --no-threads");
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -520,19 +520,19 @@ ModuleParseTask::ModuleParseTask(JSConte
     data(std::move(srcBuf))
 {}
 
 void
 ModuleParseTask::parse(JSContext* cx)
 {
     Rooted<ScriptSourceObject*> sourceObject(cx);
 
-    ModuleObject* module = frontend::CompileModule(cx, options, data, alloc, &sourceObject.get());
-    if (module) {
-        scripts.infallibleAppend(module->script());
+    JSScript* script = frontend::CompileModule(cx, options, data, alloc, &sourceObject.get());
+    if (script) {
+        scripts.infallibleAppend(script);
         if (sourceObject)
             sourceObjects.infallibleAppend(sourceObject);
     }
 }
 
 ScriptDecodeTask::ScriptDecodeTask(JSContext* cx, const JS::TranscodeRange& range,
                                    JS::OffThreadCompileCallback callback, void* callbackData)
   : ParseTask(ParseTaskKind::ScriptDecode, cx, callback, callbackData),
@@ -1801,31 +1801,31 @@ GlobalHelperThreadState::finishBinASTDec
 
 bool
 GlobalHelperThreadState::finishMultiScriptsDecodeTask(JSContext* cx, JS::OffThreadToken* token,
                                                       MutableHandle<ScriptVector> scripts)
 {
     return finishParseTask(cx, ParseTaskKind::MultiScriptsDecode, token, scripts);
 }
 
-JSObject*
+JSScript*
 GlobalHelperThreadState::finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token)
 {
-    JSScript* script = finishParseTask(cx, ParseTaskKind::Module, token);
+    RootedScript script(cx, finishParseTask(cx, ParseTaskKind::Module, token));
     if (!script)
         return nullptr;
 
     MOZ_ASSERT(script->module());
 
     RootedModuleObject module(cx, script->module());
     module->fixEnvironmentsAfterCompartmentMerge();
     if (!ModuleObject::Freeze(cx, module))
         return nullptr;
 
-    return module;
+    return script;
 }
 
 void
 GlobalHelperThreadState::cancelParseTask(JSRuntime* rt, ParseTaskKind kind,
                                          JS::OffThreadToken* token)
 {
     destroyParseTask(rt, removeFinishedParseTask(kind, token));
 }
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -301,17 +301,17 @@ class GlobalHelperThreadState
 
     void mergeParseTaskRealm(JSContext* cx, ParseTask* parseTask, JS::Realm* dest);
 
     void trace(JSTracer* trc);
 
     JSScript* finishScriptParseTask(JSContext* cx, JS::OffThreadToken* token);
     JSScript* finishScriptDecodeTask(JSContext* cx, JS::OffThreadToken* token);
     bool finishMultiScriptsDecodeTask(JSContext* cx, JS::OffThreadToken* token, MutableHandle<ScriptVector> scripts);
-    JSObject* finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token);
+    JSScript* finishModuleParseTask(JSContext* cx, JS::OffThreadToken* token);
 
 #if defined(JS_BUILD_BINAST)
     JSScript* finishBinASTDecodeTask(JSContext* cx, JS::OffThreadToken* token);
 #endif
 
     bool hasActiveThreads(const AutoLockHelperThreadState&);
     void waitForAllThreads();
     void waitForAllThreadsLocked(AutoLockHelperThreadState&);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4398,17 +4398,18 @@ CASE(JSOP_NEWTARGET)
     MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
 END_CASE(JSOP_NEWTARGET)
 
 CASE(JSOP_IMPORTMETA)
 {
     ReservedRooted<JSObject*> module(&rootObject0, GetModuleObjectForScript(script));
     MOZ_ASSERT(module);
 
-    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, module);
+    ReservedRooted<JSScript*> script(&rootScript0, module->as<ModuleObject>().script());
+    JSObject* metaObject = GetOrCreateModuleMetaObject(cx, script);
     if (!metaObject)
         goto error;
 
     PUSH_OBJECT(*metaObject);
 }
 END_CASE(JSOP_NEWTARGET)
 
 CASE(JSOP_SUPERFUN)
--- a/js/src/vm/Realm.cpp
+++ b/js/src/vm/Realm.cpp
@@ -1016,16 +1016,22 @@ JS::GetCurrentRealmOrNull(JSContext* cx)
 }
 
 JS_PUBLIC_API(JS::Realm*)
 JS::GetObjectRealmOrNull(JSObject* obj)
 {
     return IsCrossCompartmentWrapper(obj) ? nullptr : obj->nonCCWRealm();
 }
 
+JS_PUBLIC_API(JS::Realm*)
+JS::GetScriptRealm(JSScript* script)
+{
+    return script->realm();
+}
+
 JS_PUBLIC_API(void*)
 JS::GetRealmPrivate(JS::Realm* realm)
 {
     return realm->realmPrivate();
 }
 
 JS_PUBLIC_API(void)
 JS::SetRealmPrivate(JS::Realm* realm, void* data)
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2146,27 +2146,28 @@ intrinsic_HostResolveImportedModule(JSCo
     RootedString specifier(cx, args[1].toString());
 
     JS::ModuleResolveHook moduleResolveHook = cx->runtime()->moduleResolveHook;
     if (!moduleResolveHook) {
         JS_ReportErrorASCII(cx, "Module resolve hook not set");
         return false;
     }
 
-    RootedObject result(cx);
-    result = moduleResolveHook(cx, module, specifier);
+    RootedScript script(cx, module->script());
+    RootedScript result(cx);
+    result = moduleResolveHook(cx, script, specifier);
     if (!result)
         return false;
 
-    if (!result->is<ModuleObject>()) {
-        JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
+    if (!result->module()) {
+        JS_ReportErrorASCII(cx, "Module resolve hook did not return a module script");
         return false;
     }
 
-    args.rval().setObject(*result);
+    args.rval().setObject(*result->module());
     return true;
 }
 
 static bool
 intrinsic_CreateImportBinding(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     MOZ_ASSERT(args.length() == 4);
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -436,16 +436,23 @@ Scriptability::SetDocShellAllowsScript(b
 
 /* static */
 Scriptability&
 Scriptability::Get(JSObject* aScope)
 {
     return RealmPrivate::Get(aScope)->scriptability;
 }
 
+/* static */
+Scriptability&
+Scriptability::Get(JSScript* aScript)
+{
+    return RealmPrivate::Get(aScript)->scriptability;
+}
+
 bool
 IsContentXBLCompartment(JS::Compartment* compartment)
 {
     // We always eagerly create compartment privates for content XBL compartments.
     CompartmentPrivate* priv = CompartmentPrivate::Get(compartment);
     return priv && priv->isContentXBLCompartment;
 }
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2986,16 +2986,23 @@ public:
     // cross-compartment wrapper, as CCWs aren't dedicated to a particular
     // realm.
     static RealmPrivate* Get(JSObject* object)
     {
         JS::Realm* realm = JS::GetObjectRealmOrNull(object);
         return Get(realm);
     }
 
+    // Get the RealmPrivate for a given script.
+    static RealmPrivate* Get(JSScript* script)
+    {
+        JS::Realm* realm = JS::GetScriptRealm(script);
+        return Get(realm);
+    }
+
     // The scriptability of this realm.
     Scriptability scriptability;
 
     // Our XPCWrappedNativeScope. This is non-null if and only if this is an
     // XPConnect realm.
     XPCWrappedNativeScope* scope;
 
     const nsACString& GetLocation() {
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -49,16 +49,17 @@ public:
     bool Allowed();
     bool IsImmuneToScriptPolicy();
 
     void Block();
     void Unblock();
     void SetDocShellAllowsScript(bool aAllowed);
 
     static Scriptability& Get(JSObject* aScope);
+    static Scriptability& Get(JSScript* aScript);
 
 private:
     // Whenever a consumer wishes to prevent script from running on a global,
     // it increments this value with a call to Block(). When it wishes to
     // re-enable it (if ever), it decrements this value with a call to Unblock().
     // Script may not run if this value is non-zero.
     uint32_t mScriptBlocks;