Backed out 2 changesets (bug 1583816) for causing ccov crashes CLOSED TREE
authorCiure Andrei <aciure@mozilla.com>
Mon, 30 Sep 2019 21:46:51 +0300
changeset 495713 bb56e5bd22032d0fa926ab21d6952c3f227aa3b4
parent 495712 11114f961efb323c68b0ee7f0251b64860f594a9
child 495714 4836c05dd2eee11bf9d836fb0505e77450b0651b
push id114140
push userdvarga@mozilla.com
push dateWed, 02 Oct 2019 18:04:51 +0000
treeherdermozilla-inbound@32eb0ea893f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1583816
milestone71.0a1
backs out73734a2e8547b2cc72920c255b933183e70ee8ba
2736f38dd2ce83b8711c0db304fcf6cf5b62f56f
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
Backed out 2 changesets (bug 1583816) for causing ccov crashes CLOSED TREE Backed out changeset 73734a2e8547 (bug 1583816) Backed out changeset 2736f38dd2ce (bug 1583816)
js/src/debugger/Script.cpp
js/src/frontend/BytecodeCompilation.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/vm/JSScript-inl.h
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
--- a/js/src/debugger/Script.cpp
+++ b/js/src/debugger/Script.cpp
@@ -290,16 +290,30 @@ bool DebuggerScript::CallData::ToNative(
   if (!obj) {
     return false;
   }
 
   CallData data(cx, args, obj);
   return (data.*MyMethod)();
 }
 
+template <typename Result>
+Result CallScriptMethod(HandleDebuggerScript obj,
+                        Result (JSScript::*ifJSScript)() const,
+                        Result (LazyScript::*ifLazyScript)() const) {
+  if (obj->getReferent().is<JSScript*>()) {
+    JSScript* script = obj->getReferent().as<JSScript*>();
+    return (script->*ifJSScript)();
+  }
+
+  MOZ_ASSERT(obj->getReferent().is<LazyScript*>());
+  LazyScript* lazyScript = obj->getReferent().as<LazyScript*>();
+  return (lazyScript->*ifLazyScript)();
+}
+
 bool DebuggerScript::CallData::getIsGeneratorFunction() {
   if (!ensureScriptMaybeLazy()) {
     return false;
   }
   args.rval().setBoolean(obj->getReferentScript()->isGenerator());
   return true;
 }
 
@@ -311,34 +325,37 @@ bool DebuggerScript::CallData::getIsAsyn
   return true;
 }
 
 bool DebuggerScript::CallData::getIsFunction() {
   if (!ensureScriptMaybeLazy()) {
     return false;
   }
 
-  args.rval().setBoolean(obj->getReferentScript()->functionNonDelazifying());
+  // Note: LazyScripts always have functions.
+  args.rval().setBoolean(!referent.is<JSScript*>() ||
+                         referent.as<JSScript*>()->functionNonDelazifying());
   return true;
 }
 
 bool DebuggerScript::CallData::getIsModule() {
   if (!ensureScriptMaybeLazy()) {
     return false;
   }
   args.rval().setBoolean(referent.is<JSScript*>() &&
                          referent.as<JSScript*>()->isModule());
   return true;
 }
 
 bool DebuggerScript::CallData::getDisplayName() {
   if (!ensureScriptMaybeLazy()) {
     return false;
   }
-  JSFunction* func = obj->getReferentScript()->functionNonDelazifying();
+  JSFunction* func = CallScriptMethod(obj, &JSScript::functionNonDelazifying,
+                                      &LazyScript::functionNonDelazifying);
   Debugger* dbg = Debugger::fromChildJSObject(obj);
 
   JSString* name = func ? func->displayAtom() : nullptr;
   if (!name) {
     args.rval().setUndefined();
     return true;
   }
 
--- a/js/src/frontend/BytecodeCompilation.h
+++ b/js/src/frontend/BytecodeCompilation.h
@@ -88,18 +88,17 @@ class MOZ_STACK_CLASS BytecodeCompiler {
       const mozilla::Maybe<uint32_t>& parameterListEnd);
 
   void createParseInfo(LifoAllocScope& allocScope) {
     parseInfo.emplace(cx, allocScope);
   }
 
   // Create a script for source of the given length, using the explicitly-
   // provided toString offsets as the created script's offsets in the source.
-  MOZ_MUST_USE bool internalCreateScript(HandleObject functionOrGlobal,
-                                         uint32_t toStringStart,
+  MOZ_MUST_USE bool internalCreateScript(uint32_t toStringStart,
                                          uint32_t toStringEnd,
                                          uint32_t sourceBufferLength);
 
   MOZ_MUST_USE bool emplaceEmitter(mozilla::Maybe<BytecodeEmitter>& emitter,
                                    const EitherParser& parser,
                                    SharedContext* sharedContext);
 
   // This function lives here, not in SourceAwareCompiler, because it mostly
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -150,22 +150,20 @@ class MOZ_STACK_CLASS frontend::SourceAw
   MOZ_MUST_USE bool createSourceAndParser(
       LifoAllocScope& allocScope, BytecodeCompiler& compiler, ParseGoal goal,
       const Maybe<uint32_t>& parameterListEnd = Nothing());
 
   // This assumes the created script's offsets in the source used to parse it
   // are the same as are used to compute its Function.prototype.toString()
   // value.
   MOZ_MUST_USE bool createCompleteScript(BytecodeCompiler& info) {
-    JSContext* cx = info.cx;
-    RootedObject global(cx, cx->global());
     uint32_t toStringStart = 0;
     uint32_t len = sourceBuffer_.length();
     uint32_t toStringEnd = len;
-    return info.internalCreateScript(global, toStringStart, toStringEnd, len);
+    return info.internalCreateScript(toStringStart, toStringEnd, len);
   }
 
   MOZ_MUST_USE bool handleParseFailure(BytecodeCompiler& compiler,
                                        const Directives& newDirectives,
                                        TokenStreamPosition& startPosition);
 };
 
 template <typename Unit>
@@ -307,20 +305,19 @@ class MOZ_STACK_CLASS frontend::Standalo
   MOZ_MUST_USE bool compile(MutableHandleFunction fun,
                             StandaloneFunctionInfo& info,
                             FunctionNode* parsedFunction);
 
  private:
   // Create a script for a function with the given toString offsets in source
   // text.
   MOZ_MUST_USE bool createFunctionScript(StandaloneFunctionInfo& info,
-                                         HandleObject function,
                                          uint32_t toStringStart,
                                          uint32_t toStringEnd) {
-    return info.internalCreateScript(function, toStringStart, toStringEnd,
+    return info.internalCreateScript(toStringStart, toStringEnd,
                                      sourceBuffer_.length());
   }
 };
 
 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx,
                                            const TraceLoggerTextId id,
                                            const ErrorReporter& errorReporter)
 #ifdef JS_TRACE_LOGGING
@@ -449,23 +446,21 @@ bool frontend::SourceAwareCompiler<Unit>
   parser.emplace(info.cx, info.options, sourceBuffer_.units(),
                  sourceBuffer_.length(),
                  /* foldConstants = */ true, *info.parseInfo,
                  syntaxParser.ptrOr(nullptr), nullptr, info.sourceObject, goal);
   parser->ss = info.scriptSource;
   return parser->checkOptions();
 }
 
-bool BytecodeCompiler::internalCreateScript(HandleObject functionOrGlobal,
-                                            uint32_t toStringStart,
+bool BytecodeCompiler::internalCreateScript(uint32_t toStringStart,
                                             uint32_t toStringEnd,
                                             uint32_t sourceBufferLength) {
-  script = JSScript::Create(cx, functionOrGlobal, options, sourceObject,
-                            /* sourceStart = */ 0, sourceBufferLength,
-                            toStringStart, toStringEnd);
+  script = JSScript::Create(cx, options, sourceObject, /* sourceStart = */ 0,
+                            sourceBufferLength, toStringStart, toStringEnd);
   return script != nullptr;
 }
 
 bool BytecodeCompiler::emplaceEmitter(Maybe<BytecodeEmitter>& emitter,
                                       const EitherParser& parser,
                                       SharedContext* sharedContext) {
   BytecodeEmitter::EmitterMode emitterMode = options.selfHostingMode
                                                  ? BytecodeEmitter::SelfHosting
@@ -671,17 +666,17 @@ FunctionNode* frontend::StandaloneFuncti
 template <typename Unit>
 bool frontend::StandaloneFunctionCompiler<Unit>::compile(
     MutableHandleFunction fun, StandaloneFunctionInfo& info,
     FunctionNode* parsedFunction) {
   FunctionBox* funbox = parsedFunction->funbox();
   if (funbox->isInterpreted()) {
     MOZ_ASSERT(fun == funbox->function());
 
-    if (!createFunctionScript(info, fun, funbox->toStringStart,
+    if (!createFunctionScript(info, funbox->toStringStart,
                               funbox->toStringEnd)) {
       return false;
     }
 
     if (!parser->publishDeferredItems()) {
       return false;
     }
 
@@ -754,18 +749,18 @@ JSScript* frontend::CompileGlobalBinASTS
   if (!sourceObj) {
     return nullptr;
   }
 
   if (!sourceObj->source()->setBinASTSourceCopy(cx, src, len)) {
     return nullptr;
   }
 
-  RootedScript script(cx, JSScript::Create(cx, cx->global(), options, sourceObj,
-                                           0, len, 0, len));
+  RootedScript script(cx,
+                      JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
 
   if (!script) {
     return nullptr;
   }
 
   Directives directives(options.forceStrictMode());
   GlobalSharedContext globalsc(cx, ScopeKind::Global, directives,
                                options.extraWarningsOption);
@@ -1068,17 +1063,17 @@ bool frontend::CompileLazyBinASTFunction
 
   LifoAllocScope allocScope(&cx->tempLifoAlloc());
   ParseInfo pci(cx, allocScope);
 
   RootedScriptSourceObject sourceObj(cx, lazy->sourceObject());
   MOZ_ASSERT(sourceObj);
 
   RootedScript script(
-      cx, JSScript::Create(cx, fun, options, sourceObj, lazy->sourceStart(),
+      cx, JSScript::Create(cx, options, sourceObj, lazy->sourceStart(),
                            lazy->sourceEnd(), lazy->sourceStart(),
                            lazy->sourceEnd()));
 
   if (!script) {
     return false;
   }
 
   if (lazy->hasBeenCloned()) {
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -5731,17 +5731,17 @@ MOZ_NEVER_INLINE bool BytecodeEmitter::e
     // parent.  Use default values for the rest.
     Rooted<JSScript*> parent(cx, script);
     MOZ_ASSERT(parent->mutedErrors() == parser->options().mutedErrors());
     const JS::TransitiveCompileOptions& transitiveOptions = parser->options();
     JS::CompileOptions options(cx, transitiveOptions);
 
     Rooted<ScriptSourceObject*> sourceObject(cx, script->sourceObject());
     Rooted<JSScript*> innerScript(
-        cx, JSScript::Create(cx, fun, options, sourceObject, funbox->bufStart,
+        cx, JSScript::Create(cx, options, sourceObject, funbox->bufStart,
                              funbox->bufEnd, funbox->toStringStart,
                              funbox->toStringEnd));
     if (!innerScript) {
       return false;
     }
 
     EmitterMode nestedMode = emitterMode;
     if (nestedMode == BytecodeEmitter::LazyFunction) {
--- a/js/src/vm/JSScript-inl.h
+++ b/js/src/vm/JSScript-inl.h
@@ -65,31 +65,31 @@ void SetFrameArgumentsObject(JSContext* 
     return nullptr;
   }
   return fun;
 }
 
 }  // namespace js
 
 inline JSFunction* JSScript::functionDelazifying() const {
-  JSFunction* fun = functionNonDelazifying();
+  JSFunction* fun = function();
   if (fun && fun->isInterpretedLazy()) {
     fun->setUnlazifiedScript(const_cast<JSScript*>(this));
     // If this script has a LazyScript, make sure the LazyScript has a
     // reference to the script when delazifying its canonical function.
     if (lazyScript && !lazyScript->maybeScript()) {
       lazyScript->initScript(const_cast<JSScript*>(this));
     }
   }
   return fun;
 }
 
 inline void JSScript::ensureNonLazyCanonicalFunction() {
   // Infallibly delazify the canonical script.
-  JSFunction* fun = functionNonDelazifying();
+  JSFunction* fun = function();
   if (fun && fun->isInterpretedLazy()) {
     functionDelazifying();
   }
 }
 
 inline JSFunction* JSScript::getFunction(size_t index) {
   JSObject* obj = getObject(index);
   MOZ_RELEASE_ASSERT(obj->is<JSFunction>(), "Script object is not JSFunction");
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1133,22 +1133,18 @@ XDRResult js::XDRScript(XDRState<mode>* 
   } else {
     // While encoding, the ScriptSource passed in must match the ScriptSource
     // of the script.
     MOZ_ASSERT_IF(mode == XDR_ENCODE,
                   sourceObjectArg->source() == script->scriptSource());
   }
 
   if (mode == XDR_DECODE) {
-    RootedObject functionOrGlobal(cx,
-                                  fun ? static_cast<JSObject*>(fun)
-                                      : static_cast<JSObject*>(cx->global()));
-    script =
-        JSScript::Create(cx, functionOrGlobal, *options, sourceObject,
-                         sourceStart, sourceEnd, toStringStart, toStringEnd);
+    script = JSScript::Create(cx, *options, sourceObject, sourceStart,
+                              sourceEnd, toStringStart, toStringEnd);
     if (!script) {
       return xdr->fail(JS::TranscodeResult_Throw);
     }
     scriptp.set(script);
 
     script->lineno_ = lineno;
     script->column_ = column;
     script->immutableFlags_ = immutableFlags;
@@ -3808,64 +3804,61 @@ void PrivateScriptData::trace(JSTracer* 
       // due to OOM triggering the ClearEdgesTracer.
       elem = JS::GCCellPtr();
     } else if (thing != elem.asCell()) {
       elem = JS::GCCellPtr(thing, elem.kind());
     }
   }
 }
 
-JSScript::JSScript(HandleObject functionOrGlobal, uint8_t* stubEntry,
+JSScript::JSScript(HandleObject global, uint8_t* stubEntry,
                    HandleScriptSourceObject sourceObject, uint32_t sourceStart,
                    uint32_t sourceEnd, uint32_t toStringStart,
                    uint32_t toStringEnd)
-    : js::BaseScript(stubEntry, functionOrGlobal, sourceObject, sourceStart,
-                     sourceEnd, toStringStart, toStringEnd) {}
+    : js::BaseScript(stubEntry, global, sourceObject, sourceStart, sourceEnd,
+                     toStringStart, toStringEnd) {}
 
 /* static */
-JSScript* JSScript::New(JSContext* cx, HandleObject functionOrGlobal,
-                        HandleScriptSourceObject sourceObject,
+JSScript* JSScript::New(JSContext* cx, HandleScriptSourceObject sourceObject,
                         uint32_t sourceStart, uint32_t sourceEnd,
                         uint32_t toStringStart, uint32_t toStringEnd) {
   void* script = Allocate<JSScript>(cx);
   if (!script) {
     return nullptr;
   }
 
 #ifndef JS_CODEGEN_NONE
   uint8_t* stubEntry = cx->runtime()->jitRuntime()->interpreterStub().value;
 #else
   uint8_t* stubEntry = nullptr;
 #endif
 
   return new (script)
-      JSScript(functionOrGlobal, stubEntry, sourceObject, sourceStart,
-               sourceEnd, toStringStart, toStringEnd);
+      JSScript(cx->global(), stubEntry, sourceObject, sourceStart, sourceEnd,
+               toStringStart, toStringEnd);
 }
 
 static bool ShouldTrackRecordReplayProgress(JSScript* script) {
   // Progress is only tracked when recording or replaying, and only for
   // scripts associated with the main thread's runtime. Whether self hosted
   // scripts execute may depend on performed Ion optimizations (for example,
   // self hosted TypedObject logic), so they are ignored.
   return MOZ_UNLIKELY(mozilla::recordreplay::IsRecordingOrReplaying()) &&
          !script->runtimeFromAnyThread()->parentRuntime &&
          !script->selfHosted() &&
          mozilla::recordreplay::ShouldUpdateProgressCounter(script->filename());
 }
 
 /* static */
-JSScript* JSScript::Create(JSContext* cx, HandleObject functionOrGlobal,
-                           const ReadOnlyCompileOptions& options,
+JSScript* JSScript::Create(JSContext* cx, const ReadOnlyCompileOptions& options,
                            HandleScriptSourceObject sourceObject,
                            uint32_t sourceStart, uint32_t sourceEnd,
                            uint32_t toStringStart, uint32_t toStringEnd) {
-  RootedScript script(
-      cx, JSScript::New(cx, functionOrGlobal, sourceObject, sourceStart,
-                        sourceEnd, toStringStart, toStringEnd));
+  RootedScript script(cx, JSScript::New(cx, sourceObject, sourceStart,
+                                        sourceEnd, toStringStart, toStringEnd));
   if (!script) {
     return nullptr;
   }
 
   // Record compile options that get checked at runtime.
   script->setFlag(ImmutableFlags::NoScriptRval, options.noScriptRval);
   script->setFlag(ImmutableFlags::SelfHosted, options.selfHostingMode);
   script->setFlag(ImmutableFlags::TreatAsRunOnce, options.isRunOnce);
@@ -3882,21 +3875,20 @@ JSScript* JSScript::Create(JSContext* cx
   }
 
   return script;
 }
 
 /* static */ JSScript* JSScript::CreateFromLazy(JSContext* cx,
                                                 Handle<LazyScript*> lazy) {
   RootedScriptSourceObject sourceObject(cx, lazy->sourceObject());
-  RootedObject fun(cx, lazy->functionNonDelazifying());
-  RootedScript script(cx,
-                      JSScript::New(cx, fun, sourceObject, lazy->sourceStart(),
-                                    lazy->sourceEnd(), lazy->toStringStart(),
-                                    lazy->toStringEnd()));
+  RootedScript script(
+      cx,
+      JSScript::New(cx, sourceObject, lazy->sourceStart(), lazy->sourceEnd(),
+                    lazy->toStringStart(), lazy->toStringEnd()));
   if (!script) {
     return nullptr;
   }
 
   script->setFlag(MutableFlags::TrackRecordReplayProgress,
                   ShouldTrackRecordReplayProgress(script));
 
   if (coverage::IsLCovEnabled()) {
@@ -4600,17 +4592,16 @@ bool PrivateScriptData::Clone(JSContext*
       array[i] = gcThings[i].get().get();
     }
   }
 
   return true;
 }
 
 JSScript* js::detail::CopyScript(JSContext* cx, HandleScript src,
-                                 HandleObject functionOrGlobal,
                                  HandleScriptSourceObject sourceObject,
                                  MutableHandle<GCVector<Scope*>> scopes) {
   // We don't copy the HideScriptFromDebugger flag and it's not clear what
   // should happen if it's set on the source script.
   MOZ_ASSERT(!src->hideScriptFromDebugger());
 
   if (src->treatAsRunOnce() && !src->functionNonDelazifying()) {
     JS_ReportErrorASCII(cx, "No cloning toplevel run-once scripts");
@@ -4623,20 +4614,20 @@ JSScript* js::detail::CopyScript(JSConte
   JS::AssertObjectIsNotGray(sourceObject);
 
   CompileOptions options(cx);
   options.setMutedErrors(src->mutedErrors())
       .setSelfHostingMode(src->selfHosted())
       .setNoScriptRval(src->noScriptRval());
 
   // Create a new JSScript to fill in
-  RootedScript dst(cx,
-                   JSScript::Create(cx, functionOrGlobal, options, sourceObject,
-                                    src->sourceStart(), src->sourceEnd(),
-                                    src->toStringStart(), src->toStringEnd()));
+  RootedScript dst(
+      cx, JSScript::Create(cx, options, sourceObject, src->sourceStart(),
+                           src->sourceEnd(), src->toStringStart(),
+                           src->toStringEnd()));
   if (!dst) {
     return nullptr;
   }
 
   // Copy POD fields
   dst->lineno_ = src->lineno();
   dst->column_ = src->column();
   dst->immutableFlags_ = src->immutableFlags();
@@ -4679,18 +4670,17 @@ JSScript* js::CloneGlobalScript(JSContex
   MOZ_ASSERT(src->bodyScopeIndex() == 0);
   Rooted<GCVector<Scope*>> scopes(cx, GCVector<Scope*>(cx));
   Rooted<GlobalScope*> original(cx, &src->bodyScope()->as<GlobalScope>());
   GlobalScope* clone = GlobalScope::clone(cx, original, scopeKind);
   if (!clone || !scopes.append(clone)) {
     return nullptr;
   }
 
-  RootedObject global(cx, cx->global());
-  return detail::CopyScript(cx, src, global, sourceObject, &scopes);
+  return detail::CopyScript(cx, src, sourceObject, &scopes);
 }
 
 JSScript* js::CloneScriptIntoFunction(
     JSContext* cx, HandleScope enclosingScope, HandleFunction fun,
     HandleScript src, Handle<ScriptSourceObject*> sourceObject) {
   MOZ_ASSERT(fun->isInterpreted());
   MOZ_ASSERT(!fun->hasScript() || fun->hasUncompletedScript());
 
@@ -4718,17 +4708,17 @@ JSScript* js::CloneScriptIntoFunction(
 
     if (!clone || !scopes.append(clone)) {
       return nullptr;
     }
   }
 
   // Save flags in case we need to undo the early mutations.
   const FunctionFlags preservedFlags = fun->flags();
-  RootedScript dst(cx, detail::CopyScript(cx, src, fun, sourceObject, &scopes));
+  RootedScript dst(cx, detail::CopyScript(cx, src, sourceObject, &scopes));
   if (!dst) {
     fun->setFlags(preservedFlags);
     return nullptr;
   }
 
   // Finally set the script after all the fallible operations.
   if (fun->isInterpretedLazy()) {
     fun->setUnlazifiedScript(dst);
--- a/js/src/vm/JSScript.h
+++ b/js/src/vm/JSScript.h
@@ -86,17 +86,16 @@ namespace gc {
 void SweepLazyScripts(GCParallelTask* task);
 }  // namespace gc
 
 namespace detail {
 
 // Do not call this directly! It is exposed for the friend declarations in
 // this file.
 JSScript* CopyScript(JSContext* cx, HandleScript src,
-                     HandleObject functionOrGlobal,
                      HandleScriptSourceObject sourceObject,
                      MutableHandle<GCVector<Scope*>> scopes);
 
 }  // namespace detail
 
 }  // namespace js
 
 /*
@@ -1510,17 +1509,17 @@ class BaseScript : public gc::TenuredCel
 
     NeedsHomeObject = 1 << 13,
 
     IsDerivedClassConstructor = 1 << 14,
     IsDefaultClassConstructor = 1 << 15,
 
     // Script is a lambda to treat as running once or a global or eval script
     // that will only run once.  Which one it is can be disambiguated by
-    // checking whether functionNonDelazifying() is null.
+    // checking whether function() is null.
     TreatAsRunOnce = 1 << 16,
 
     // 'this', 'arguments' and f.apply() are used. This is likely to be a
     // wrapper.
     IsLikelyConstructorWrapper = 1 << 17,
 
     // Set if this function is a generator function or async generator.
     IsGenerator = 1 << 18,
@@ -1633,23 +1632,16 @@ class BaseScript : public gc::TenuredCel
   uint8_t* jitCodeRaw() const { return jitCodeRaw_; }
 
   JS::Realm* realm() const { return functionOrGlobal_->nonCCWRealm(); }
   JS::Compartment* compartment() const {
     return functionOrGlobal_->compartment();
   }
   JS::Compartment* maybeCompartment() const { return compartment(); }
 
-  JSFunction* functionNonDelazifying() const {
-    if (functionOrGlobal_->is<JSFunction>()) {
-      return &functionOrGlobal_->as<JSFunction>();
-    }
-    return nullptr;
-  }
-
   ScriptSourceObject* sourceObject() const { return sourceObject_; }
   ScriptSource* scriptSource() const { return sourceObject()->source(); }
   ScriptSource* maybeForwardedScriptSource() const;
 
   bool mutedErrors() const { return scriptSource()->mutedErrors(); }
 
   const char* filename() const { return scriptSource()->filename(); }
   const char* maybeForwardedFilename() const {
@@ -2409,32 +2401,31 @@ class JSScript : public js::BaseScript {
       JSContext* cx, js::HandleScript src, js::HandleScript dst,
       js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
 
   friend bool js::PrivateScriptData::InitFromEmitter(
       JSContext* cx, js::HandleScript script,
       js::frontend::BytecodeEmitter* bce);
 
   friend JSScript* js::detail::CopyScript(
-      JSContext* cx, js::HandleScript src, js::HandleObject functionOrGlobal,
+      JSContext* cx, js::HandleScript src,
       js::HandleScriptSourceObject sourceObject,
       js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
 
  private:
-  JSScript(js::HandleObject functionOrGlobal, uint8_t* stubEntry,
+  JSScript(js::HandleObject global, uint8_t* stubEntry,
            js::HandleScriptSourceObject sourceObject, uint32_t sourceStart,
            uint32_t sourceEnd, uint32_t toStringStart, uint32_t toStringend);
 
-  static JSScript* New(JSContext* cx, js::HandleObject functionOrGlobal,
-                       js::HandleScriptSourceObject sourceObject,
+  static JSScript* New(JSContext* cx, js::HandleScriptSourceObject sourceObject,
                        uint32_t sourceStart, uint32_t sourceEnd,
                        uint32_t toStringStart, uint32_t toStringEnd);
 
  public:
-  static JSScript* Create(JSContext* cx, js::HandleObject functionOrGlobal,
+  static JSScript* Create(JSContext* cx,
                           const JS::ReadOnlyCompileOptions& options,
                           js::HandleScriptSourceObject sourceObject,
                           uint32_t sourceStart, uint32_t sourceEnd,
                           uint32_t toStringStart, uint32_t toStringEnd);
 
   static JSScript* CreateFromLazy(JSContext* cx,
                                   js::Handle<js::LazyScript*> lazy);
 
@@ -2680,16 +2671,22 @@ class JSScript : public js::BaseScript {
    * Original compiled function for the script, if it has a function.
    * nullptr for global and eval scripts.
    * The delazifying variant ensures that the function isn't lazy. The
    * non-delazifying variant must only be used after earlier code has
    * called ensureNonLazyCanonicalFunction and while the function can't
    * have been relazified.
    */
   inline JSFunction* functionDelazifying() const;
+  JSFunction* functionNonDelazifying() const {
+    if (bodyScope()->is<js::FunctionScope>()) {
+      return bodyScope()->as<js::FunctionScope>().canonicalFunction();
+    }
+    return nullptr;
+  }
   /*
    * De-lazifies the canonical function. Must be called before entering code
    * that expects the function to be non-lazy.
    */
   inline void ensureNonLazyCanonicalFunction();
 
   bool isModule() const {
     MOZ_ASSERT(hasFlag(ImmutableFlags::IsModule) ==
@@ -3009,16 +3006,23 @@ class JSScript : public js::BaseScript {
     MOZ_ASSERT(js::JOF_OPTYPE(JSOp(*pc)) == JOF_SCOPE,
                "Did you mean to use lookupScope(pc)?");
     return getScope(GET_UINT32_INDEX(pc));
   }
 
   inline JSFunction* getFunction(size_t index);
   inline JSFunction* getFunction(jsbytecode* pc);
 
+  JSFunction* function() const {
+    if (functionNonDelazifying()) {
+      return functionNonDelazifying();
+    }
+    return nullptr;
+  }
+
   inline js::RegExpObject* getRegExp(size_t index);
   inline js::RegExpObject* getRegExp(jsbytecode* pc);
 
   js::BigInt* getBigInt(size_t index) {
     return &gcthings()[index].as<js::BigInt>();
   }
 
   js::BigInt* getBigInt(jsbytecode* pc) {
@@ -3284,16 +3288,20 @@ class LazyScript : public BaseScript {
       JSContext* cx, uint32_t numClosedOverBindings, uint32_t numInnerFunctions,
       HandleFunction fun, HandleScript script, HandleScope enclosingScope,
       HandleScriptSourceObject sourceObject, uint32_t immutableFlags,
       uint32_t sourceStart, uint32_t sourceEnd, uint32_t toStringStart,
       uint32_t toStringEnd, uint32_t lineno, uint32_t column);
 
   static inline JSFunction* functionDelazifying(JSContext* cx,
                                                 Handle<LazyScript*>);
+  JSFunction* functionNonDelazifying() const {
+    return &functionOrGlobal_->as<JSFunction>();
+  }
+
   void initScript(JSScript* script);
 
   JSScript* maybeScript() { return script_; }
   const JSScript* maybeScriptUnbarriered() const {
     return script_.unbarrieredGet();
   }
   bool hasScript() const { return bool(script_); }