Bug 1320408 - Part 2: Change JSFunction::getOrCreateScript to static method. r=jandem
authorTooru Fujisawa <arai_a@mac.com>
Mon, 28 Nov 2016 12:29:17 +0900
changeset 324395 6b4e659892cee5ac0d89931f79bdf367807bf3c2
parent 324394 20c75f210e9a2abb0d6a932adb69b88a27579846
child 324396 b509be16fc198e36e326f7fead273c273e3cd207
push id34681
push usercbook@mozilla.com
push dateMon, 28 Nov 2016 15:49:46 +0000
treeherderautoland@2348f42371f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1320408
milestone53.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 1320408 - Part 2: Change JSFunction::getOrCreateScript to static method. r=jandem
js/src/builtin/RegExp.cpp
js/src/builtin/TestingFunctions.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/jit/IonAnalysis.cpp
js/src/jit/IonAnalysis.h
js/src/jit/IonBuilder.cpp
js/src/jit/VMFunctions.cpp
js/src/jsapi-tests/testUbiNode.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jscompartment.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jsscript.cpp
js/src/jsscriptinlines.h
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/ObjectGroup.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/Stack-inl.h
js/src/vm/TypeInference.cpp
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -1754,17 +1754,17 @@ js::intrinsic_GetElemBaseForLambda(JSCon
 
     if (!lambda.is<JSFunction>())
         return true;
 
     RootedFunction fun(cx, &lambda.as<JSFunction>());
     if (!fun->isInterpreted() || fun->isClassConstructor())
         return true;
 
-    JSScript* script = fun->getOrCreateScript(cx);
+    JSScript* script = JSFunction::getOrCreateScript(cx, fun);
     if (!script)
         return false;
 
     jsbytecode* pc = script->code();
 
     /*
      * JSOP_GETALIASEDVAR tells us exactly where to find the base object 'b'.
      * Rule out the (unlikely) possibility of a function with environment
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -3269,23 +3269,23 @@ ByteSizeOfScript(JSContext*cx, unsigned 
     CallArgs args = CallArgsFromVp(argc, vp);
     if (!args.requireAtLeast(cx, "byteSizeOfScript", 1))
         return false;
     if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
         JS_ReportErrorASCII(cx, "Argument must be a Function object");
         return false;
     }
 
-    JSFunction* fun = &args[0].toObject().as<JSFunction>();
+    RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
     if (fun->isNative()) {
         JS_ReportErrorASCII(cx, "Argument must be a scripted function");
         return false;
     }
 
-    RootedScript script(cx, fun->getOrCreateScript(cx));
+    RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
     if (!script)
         return false;
 
     mozilla::MallocSizeOf mallocSizeOf = cx->runtime()->debuggerMallocSizeOf;
 
     {
         // We can't tolerate the GC moving things around while we're using a
         // ubi::Node. Check that nothing we do causes a GC.
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -281,17 +281,18 @@ BytecodeCompiler::handleParseFailure(con
 }
 
 bool
 BytecodeCompiler::deoptimizeArgumentsInEnclosingScripts(JSContext* cx, HandleObject environment)
 {
     RootedObject env(cx, environment);
     while (env->is<EnvironmentObject>() || env->is<DebugEnvironmentProxy>()) {
         if (env->is<CallObject>()) {
-            RootedScript script(cx, env->as<CallObject>().callee().getOrCreateScript(cx));
+            RootedFunction fun(cx, &env->as<CallObject>().callee());
+            RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
             if (!script)
                 return false;
             if (script->argumentsHasVarBinding()) {
                 if (!JSScript::argumentsOptimizationFailed(cx, script))
                     return false;
             }
         }
         env = env->enclosingEnvironment();
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -4110,27 +4110,27 @@ AnalyzePoppedThis(JSContext* cx, ObjectG
 static int
 CmpInstructions(const void* a, const void* b)
 {
     return (*static_cast<MInstruction * const*>(a))->id() -
            (*static_cast<MInstruction * const*>(b))->id();
 }
 
 bool
-jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun,
+jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
                                         ObjectGroup* group, HandlePlainObject baseobj,
                                         Vector<TypeNewScript::Initializer>* initializerList)
 {
     MOZ_ASSERT(cx->zone()->types.activeAnalysis);
 
     // When invoking 'new' on the specified script, try to find some properties
     // which will definitely be added to the created object before it has a
     // chance to escape and be accessed elsewhere.
 
-    RootedScript script(cx, fun->getOrCreateScript(cx));
+    RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
     if (!script)
         return false;
 
     if (!jit::IsIonEnabled(cx) || !jit::IsBaselineEnabled(cx) || !script->canBaselineCompile())
         return true;
 
     static const uint32_t MAX_SCRIPT_SIZE = 2000;
     if (script->length() > MAX_SCRIPT_SIZE)
--- a/js/src/jit/IonAnalysis.h
+++ b/js/src/jit/IonAnalysis.h
@@ -191,17 +191,17 @@ ConvertLinearSum(TempAllocator& alloc, M
                  bool convertConstant = false);
 
 // Convert the test 'sum >= 0' to a comparison, adding any necessary
 // instructions to the end of block.
 MCompare*
 ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum);
 
 MOZ_MUST_USE bool
-AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun,
+AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
                                    ObjectGroup* group, HandlePlainObject baseobj,
                                    Vector<TypeNewScript::Initializer>* initializerList);
 
 MOZ_MUST_USE bool
 AnalyzeArgumentsUsage(JSContext* cx, JSScript* script);
 
 bool
 DeadIfUnused(const MDefinition* def);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -462,17 +462,18 @@ IonBuilder::canInlineTarget(JSFunction* 
                 return DontInline(nullptr, "Empty TypeSet for argument");
             }
         }
     }
 
     // Allow constructing lazy scripts when performing the definite properties
     // analysis, as baseline has not been used to warm the caller up yet.
     if (target->isInterpreted() && info().analysisMode() == Analysis_DefiniteProperties) {
-        RootedScript script(analysisContext, target->getOrCreateScript(analysisContext));
+        RootedFunction fun(analysisContext, target);
+        RootedScript script(analysisContext, JSFunction::getOrCreateScript(analysisContext, fun));
         if (!script)
             return InliningDecision_Error;
 
         if (!script->hasBaselineScript() && script->canBaselineCompile()) {
             MethodStatus status = BaselineCompile(analysisContext, script);
             if (status == Method_Error)
                 return InliningDecision_Error;
             if (status != Method_Compiled) {
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -555,17 +555,17 @@ GetIntrinsicValue(JSContext* cx, HandleP
 bool
 CreateThis(JSContext* cx, HandleObject callee, HandleObject newTarget, MutableHandleValue rval)
 {
     rval.set(MagicValue(JS_IS_CONSTRUCTING));
 
     if (callee->is<JSFunction>()) {
         RootedFunction fun(cx, &callee->as<JSFunction>());
         if (fun->isInterpreted() && fun->isConstructor()) {
-            JSScript* script = fun->getOrCreateScript(cx);
+            JSScript* script = JSFunction::getOrCreateScript(cx, fun);
             if (!script || !script->ensureHasTypes(cx))
                 return false;
             if (fun->isBoundFunction() || script->isDerivedClassConstructor()) {
                 rval.set(MagicValue(JS_UNINITIALIZED_LEXICAL));
             } else {
                 JSObject* thisObj = CreateThisForFunction(cx, callee, newTarget, GenericObject);
                 if (!thisObj)
                     return false;
--- a/js/src/jsapi-tests/testUbiNode.cpp
+++ b/js/src/jsapi-tests/testUbiNode.cpp
@@ -641,17 +641,17 @@ BEGIN_TEST(test_JS_ubi_Node_scriptFilena
                    &val));
 
     CHECK(val.isObject());
     JS::RootedObject obj(cx, &val.toObject());
 
     CHECK(obj->is<JSFunction>());
     JS::RootedFunction func(cx, &obj->as<JSFunction>());
 
-    JS::RootedScript script(cx, func->getOrCreateScript(cx));
+    JS::RootedScript script(cx, JSFunction::getOrCreateScript(cx, func));
     CHECK(script);
     CHECK(script->filename());
 
     JS::ubi::Node node(script);
     const char* filename = node.scriptFilename();
     CHECK(filename);
     CHECK(strcmp(filename, script->filename()) == 0);
     CHECK(strcmp(filename, "my-cool-filename.js") == 0);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3524,17 +3524,17 @@ CloneFunctionObject(JSContext* cx, Handl
         RootedValue v(cx, ObjectValue(*funobj));
         ReportIsNotFunction(cx, v);
         return nullptr;
     }
 
     RootedFunction fun(cx, &funobj->as<JSFunction>());
     if (fun->isInterpretedLazy()) {
         AutoCompartment ac(cx, funobj);
-        if (!fun->getOrCreateScript(cx))
+        if (!JSFunction::getOrCreateScript(cx, fun))
             return nullptr;
     }
 
     if (!IsFunctionCloneable(fun)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
         return nullptr;
     }
 
@@ -3556,17 +3556,17 @@ CloneFunctionObject(JSContext* cx, Handl
     if (CanReuseScriptForClone(cx->compartment(), fun, env)) {
         // If the script is to be reused, either the script can already handle
         // non-syntactic scopes, or there is only the standard global lexical
         // scope.
 #ifdef DEBUG
         // Fail here if we OOM during debug asserting.
         // CloneFunctionReuseScript will delazify the script anyways, so we
         // are not creating an extra failure condition for DEBUG builds.
-        if (!fun->getOrCreateScript(cx))
+        if (!JSFunction::getOrCreateScript(cx, fun))
             return nullptr;
         MOZ_ASSERT(scope->as<GlobalScope>().isSyntactic() ||
                    fun->nonLazyScript()->hasNonSyntacticScope());
 #endif
         return CloneFunctionReuseScript(cx, fun, env, fun->getAllocKind());
     }
 
     JSFunction* clone = CloneFunctionAndScript(cx, fun, env, scope, fun->getAllocKind());
@@ -4211,17 +4211,17 @@ JS_GetScriptBaseLineNumber(JSContext* cx
 
 JS_PUBLIC_API(JSScript*)
 JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
 {
     if (fun->isNative())
         return nullptr;
     if (fun->isInterpretedLazy()) {
         AutoCompartment funCompartment(cx, fun);
-        JSScript* script = fun->getOrCreateScript(cx);
+        JSScript* script = JSFunction::getOrCreateScript(cx, fun);
         if (!script)
             MOZ_CRASH();
         return script;
     }
     return fun->nonLazyScript();
 }
 
 /*
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1707,21 +1707,21 @@ MatchNumericComparator(JSContext* cx, co
 {
     if (!v.isObject())
         return Match_None;
 
     JSObject& obj = v.toObject();
     if (!obj.is<JSFunction>())
         return Match_None;
 
-    JSFunction* fun = &obj.as<JSFunction>();
+    RootedFunction fun(cx, &obj.as<JSFunction>());
     if (!fun->isInterpreted() || fun->isClassConstructor())
         return Match_None;
 
-    JSScript* script = fun->getOrCreateScript(cx);
+    JSScript* script = JSFunction::getOrCreateScript(cx, fun);
     if (!script)
         return Match_Failure;
 
     jsbytecode* pc = script->code();
 
     uint16_t arg0, arg1;
     if (JSOp(*pc) != JSOP_GETARG)
         return Match_None;
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -1047,28 +1047,28 @@ CreateLazyScriptsForCompartment(JSContex
     // Methods, for instance {get method() {}}, are extended functions that can
     // be relazified, so we need to handle those as well.
     if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION_EXTENDED))
         return false;
 
     // Create scripts for each lazy function, updating the list of functions to
     // process with any newly exposed inner functions in created scripts.
     // A function cannot be delazified until its outer script exists.
+    RootedFunction fun(cx);
     for (size_t i = 0; i < lazyFunctions.length(); i++) {
-        JSFunction* fun = &lazyFunctions[i]->as<JSFunction>();
+        fun = &lazyFunctions[i]->as<JSFunction>();
 
         // lazyFunctions may have been populated with multiple functions for
         // a lazy script.
         if (!fun->isInterpretedLazy())
             continue;
 
-        LazyScript* lazy = fun->lazyScript();
-        bool lazyScriptHadNoScript = !lazy->maybeScript();
+        bool lazyScriptHadNoScript = !fun->lazyScript()->maybeScript();
 
-        JSScript* script = fun->getOrCreateScript(cx);
+        JSScript* script = JSFunction::getOrCreateScript(cx, fun);
         if (!script)
             return false;
         if (lazyScriptHadNoScript && !AddInnerLazyFunctionsFromScript(script, lazyFunctions))
             return false;
     }
 
     return true;
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -933,17 +933,17 @@ const Class JSFunction::class_ = {
     &JSFunctionClassSpec
 };
 
 const Class* const js::FunctionClassPtr = &JSFunction::class_;
 
 JSString*
 js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
 {
-    if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
+    if (fun->isInterpretedLazy() && !JSFunction::getOrCreateScript(cx, fun))
         return nullptr;
 
     if (IsAsmJSModule(fun))
         return AsmJSModuleToString(cx, fun, !prettyPrint);
     if (IsAsmJSFunction(fun))
         return AsmJSFunctionToString(cx, fun);
 
     if (IsWrappedAsyncFunction(fun)) {
@@ -1268,17 +1268,17 @@ JSFunction::isDerivedClassConstructor()
     MOZ_ASSERT_IF(derived, isClassConstructor());
     return derived;
 }
 
 /* static */ bool
 JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length)
 {
     MOZ_ASSERT(!fun->isBoundFunction());
-    if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
+    if (fun->isInterpretedLazy() && !getOrCreateScript(cx, fun))
         return false;
 
     *length = fun->hasScript() ? fun->nonLazyScript()->funLength()
                                : (fun->nargs() - fun->hasRest());
     return true;
 }
 
 /* static */ bool
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -399,26 +399,25 @@ class JSFunction : public js::NativeObje
     //
     // - For inlined functions which may have a LazyScript but whose JSScript
     //   is known to exist, existingScript() will get the script and delazify
     //   the function if necessary. If the function should not be delazified,
     //   use existingScriptNonDelazifying().
     //
     // - For functions known to have a JSScript, nonLazyScript() will get it.
 
-    JSScript* getOrCreateScript(JSContext* cx) {
-        MOZ_ASSERT(isInterpreted());
+    static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) {
+        MOZ_ASSERT(fun->isInterpreted());
         MOZ_ASSERT(cx);
-        if (isInterpretedLazy()) {
-            JS::RootedFunction self(cx, this);
-            if (!createScriptForLazilyInterpretedFunction(cx, self))
+        if (fun->isInterpretedLazy()) {
+            if (!createScriptForLazilyInterpretedFunction(cx, fun))
                 return nullptr;
-            return self->nonLazyScript();
+            return fun->nonLazyScript();
         }
-        return nonLazyScript();
+        return fun->nonLazyScript();
     }
 
     JSScript* existingScriptNonDelazifying() const {
         MOZ_ASSERT(isInterpreted());
         if (isInterpretedLazy()) {
             // Get the script from the canonical function. Ion used the
             // canonical function to inline the script and because it has
             // Baseline code it has not been relazified. Note that we can't
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -83,17 +83,17 @@ CloneFunctionObjectIfNotSingleton(JSCont
     gc::AllocKind extendedFinalizeKind = gc::AllocKind::FUNCTION_EXTENDED;
     gc::AllocKind kind = fun->isExtended()
                          ? extendedFinalizeKind
                          : finalizeKind;
 
     if (CanReuseScriptForClone(cx->compartment(), fun, parent))
         return CloneFunctionReuseScript(cx, fun, parent, kind, newKind, proto);
 
-    RootedScript script(cx, fun->getOrCreateScript(cx));
+    RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
     if (!script)
         return nullptr;
     RootedScope enclosingScope(cx, script->enclosingScope());
     return CloneFunctionAndScript(cx, fun, parent, enclosingScope, kind, proto);
 }
 
 } /* namespace js */
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -946,17 +946,17 @@ js::CreateThisForFunctionWithProto(JSCon
         }
 
         res = CreateThisForFunctionWithGroup(cx, group, newKind);
     } else {
         res = NewBuiltinClassInstance<PlainObject>(cx, newKind);
     }
 
     if (res) {
-        JSScript* script = callee->as<JSFunction>().getOrCreateScript(cx);
+        JSScript* script = JSFunction::getOrCreateScript(cx, callee.as<JSFunction>());
         if (!script)
             return nullptr;
         TypeScript::SetThis(cx, script, TypeSet::ObjectType(res));
     }
 
     return res;
 }
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -2134,16 +2134,17 @@ GenerateLcovInfo(JSContext* cx, JSCompar
 
         // We found the top-level script, visit all the functions reachable
         // from the top-level function, and delazify them.
         Rooted<ScriptVector> queue(cx, ScriptVector(cx));
         if (!queue.append(topLevel))
             return false;
 
         RootedScript script(cx);
+        RootedFunction fun(cx);
         do {
             script = queue.popCopy();
             compCover.collectCodeCoverageInfo(comp, script->sourceObject(), script);
 
             // Iterate from the last to the first object in order to have
             // the functions them visited in the opposite order when popping
             // elements from the stack of remaining scripts, such that the
             // functions are more-less listed with increasing line numbers.
@@ -2151,25 +2152,25 @@ GenerateLcovInfo(JSContext* cx, JSCompar
                 continue;
             size_t idx = script->objects()->length;
             while (idx--) {
                 JSObject* obj = script->getObject(idx);
 
                 // Only continue on JSFunction objects.
                 if (!obj->is<JSFunction>())
                     continue;
-                JSFunction& fun = obj->as<JSFunction>();
+                fun = &obj->as<JSFunction>();
 
                 // Let's skip wasm for now.
-                if (!fun.isInterpreted())
+                if (!fun->isInterpreted())
                     continue;
 
                 // Queue the script in the list of script associated to the
                 // current source.
-                JSScript* childScript = fun.getOrCreateScript(cx);
+                JSScript* childScript = JSFunction::getOrCreateScript(cx, fun);
                 if (!childScript || !queue.append(childScript))
                     return false;
             }
         } while (!queue.empty());
     }
 
     bool isEmpty = true;
     compCover.exportInto(out, &isEmpty);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3220,17 +3220,17 @@ js::detail::CopyScript(JSContext* cx, Ha
                         MOZ_ASSERT(innerFun->isAsmJSNative());
                         JS_ReportErrorASCII(cx, "AsmJS modules do not yet support cloning.");
                         return false;
                     }
                     clone = innerFun;
                 } else {
                     if (innerFun->isInterpretedLazy()) {
                         AutoCompartment ac(cx, innerFun);
-                        if (!innerFun->getOrCreateScript(cx))
+                        if (!JSFunction::getOrCreateScript(cx, innerFun))
                             return false;
                     }
 
                     Scope* enclosing = innerFun->nonLazyScript()->enclosingScope();
                     RootedScope enclosingClone(cx, scopes[FindScopeIndex(src, *enclosing)]);
                     clone = CloneInnerInterpretedFunction(cx, enclosingClone, innerFun);
                 }
             } else {
@@ -4237,17 +4237,17 @@ JSScript::AutoDelazify::holdScript(JS::H
         if (fun->compartment()->isSelfHosting) {
             // The self-hosting compartment is shared across runtimes, so we
             // can't use JSAutoCompartment: it could cause races. Functions in
             // the self-hosting compartment will never be lazy, so we can safely
             // assume we don't have to delazify.
             script_ = fun->nonLazyScript();
         } else {
             JSAutoCompartment ac(cx_, fun);
-            script_ = fun->getOrCreateScript(cx_);
+            script_ = JSFunction::getOrCreateScript(cx_, fun);
             if (script_) {
                 oldDoNotRelazify_ = script_->doNotRelazify_;
                 script_->setDoNotRelazify(true);
             }
         }
     }
 }
 
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -73,17 +73,18 @@ ScriptAndCounts::ScriptAndCounts(ScriptA
 void
 SetFrameArgumentsObject(JSContext* cx, AbstractFramePtr frame,
                         HandleScript script, JSObject* argsobj);
 
 inline JSFunction*
 LazyScript::functionDelazifying(JSContext* cx) const
 {
     Rooted<const LazyScript*> self(cx, this);
-    if (self->function_ && !self->function_->getOrCreateScript(cx))
+    RootedFunction fun(cx, self->function_);
+    if (self->function_ && !JSFunction::getOrCreateScript(cx, fun))
         return nullptr;
     return self->function_;
 }
 
 } // namespace js
 
 inline JSFunction*
 JSScript::functionDelazifying() const
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2308,17 +2308,17 @@ ValueToScript(JSContext* cx, HandleValue
     if (IsWrappedAsyncFunction(fun))
         fun = GetUnwrappedAsyncFunction(fun);
 
     if (!fun->isInterpreted()) {
         JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_SCRIPTS_ONLY);
         return nullptr;
     }
 
-    JSScript* script = fun->getOrCreateScript(cx);
+    JSScript* script = JSFunction::getOrCreateScript(cx, fun);
     if (!script)
         return nullptr;
 
     if (funp)
         *funp = fun;
 
     return script;
 }
@@ -2708,17 +2708,17 @@ DisassembleScript(JSContext* cx, HandleS
         for (unsigned i = 0; i != objects->length; ++i) {
             JSObject* obj = objects->vector[i];
             if (obj->is<JSFunction>()) {
                 if (sp->put("\n") < 0)
                     return false;
 
                 RootedFunction fun(cx, &obj->as<JSFunction>());
                 if (fun->isInterpreted()) {
-                    RootedScript script(cx, fun->getOrCreateScript(cx));
+                    RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
                     if (script) {
                         if (!DisassembleScript(cx, script, fun, lines, recursive, sourceNotes, sp))
                             return false;
                     }
                 } else {
                     if (sp->put("[native code]\n") < 0)
                         return false;
                 }
@@ -5362,17 +5362,17 @@ DumpScopeChain(JSContext* cx, unsigned a
     RootedScript script(cx);
 
     if (obj->is<JSFunction>()) {
         RootedFunction fun(cx, &obj->as<JSFunction>());
         if (!fun->isInterpreted()) {
             ReportUsageErrorASCII(cx, callee, "Argument must be an interpreted function");
             return false;
         }
-        script = fun->getOrCreateScript(cx);
+        script = JSFunction::getOrCreateScript(cx, fun);
     } else {
         script = obj->as<ModuleObject>().script();
     }
 
     script->bodyScope()->dump();
 
     args.rval().setUndefined();
     return true;
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -468,17 +468,17 @@ MappedArgSetter(JSContext* cx, HandleObj
     if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
         return false;
     MOZ_ASSERT(desc.object());
     unsigned attrs = desc.attributes();
     MOZ_ASSERT(!(attrs & JSPROP_READONLY));
     attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
 
     RootedFunction callee(cx, &argsobj->callee());
-    RootedScript script(cx, callee->getOrCreateScript(cx));
+    RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
     if (!script)
         return false;
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) {
             argsobj->setElement(cx, arg, vp);
             if (arg < script->functionNonDelazifying()->nargs())
@@ -623,17 +623,17 @@ MappedArgumentsObject::obj_definePropert
     if (isMapped) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (desc.isAccessorDescriptor()) {
             if (!argsobj->markElementDeleted(cx, arg))
                 return false;
         } else {
             if (desc.hasValue()) {
                 RootedFunction callee(cx, &argsobj->callee());
-                RootedScript script(cx, callee->getOrCreateScript(cx));
+                RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
                 if (!script)
                     return false;
                 argsobj->setElement(cx, arg, desc.value());
                 if (arg < script->functionNonDelazifying()->nargs())
                     TypeScript::SetArgument(cx, script, arg, desc.value());
             }
             if (desc.hasWritable() && !desc.writable()) {
                 if (!argsobj->markElementDeleted(cx, arg))
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -220,17 +220,17 @@ static const Class DebuggerSource_class 
 
 /*** Utils ***************************************************************************************/
 
 static inline bool
 EnsureFunctionHasScript(JSContext* cx, HandleFunction fun)
 {
     if (fun->isInterpretedLazy()) {
         AutoCompartment ac(cx, fun);
-        return !!fun->getOrCreateScript(cx);
+        return !!JSFunction::getOrCreateScript(cx, fun);
     }
     return true;
 }
 
 static inline JSScript*
 GetOrCreateFunctionScript(JSContext* cx, HandleFunction fun)
 {
     MOZ_ASSERT(fun->isInterpreted());
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -1415,17 +1415,18 @@ class DebugEnvironmentProxyHandler : pub
         if (env->is<ModuleEnvironmentObject>()) {
             /* Everything is aliased and stored in the environment object. */
             return true;
         }
 
         /* Handle unaliased formals, vars, lets, and consts at function scope. */
         if (env->is<CallObject>()) {
             CallObject& callobj = env->as<CallObject>();
-            RootedScript script(cx, callobj.callee().getOrCreateScript(cx));
+            RootedFunction fun(cx, &callobj.callee());
+            RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
             if (!script->ensureHasTypes(cx) || !script->ensureHasAnalyzedArgsUsage(cx))
                 return false;
 
             BindingIter bi(script);
             while (bi && NameToId(bi.name()->asPropertyName()) != id)
                 bi++;
             if (!bi)
                 return true;
@@ -2950,17 +2951,17 @@ GetDebugEnvironment(JSContext* cx, const
 
 JSObject*
 js::GetDebugEnvironmentForFunction(JSContext* cx, HandleFunction fun)
 {
     assertSameCompartment(cx, fun);
     MOZ_ASSERT(CanUseDebugEnvironmentMaps(cx));
     if (!DebugEnvironments::updateLiveEnvironments(cx))
         return nullptr;
-    JSScript* script = fun->getOrCreateScript(cx);
+    JSScript* script = JSFunction::getOrCreateScript(cx, fun);
     if (!script)
         return nullptr;
     EnvironmentIter ei(cx, fun->environment(), script->enclosingScope());
     return GetDebugEnvironment(cx, ei);
 }
 
 JSObject*
 js::GetDebugEnvironmentForFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc)
@@ -3458,21 +3459,23 @@ RemoveReferencedNames(JSContext* cx, Han
         }
 
         if (name)
             remainingNames.remove(name);
     }
 
     if (script->hasObjects()) {
         ObjectArray* objects = script->objects();
+        RootedFunction fun(cx);
+        RootedScript innerScript(cx);
         for (size_t i = 0; i < objects->length; i++) {
             JSObject* obj = objects->vector[i];
             if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
-                JSFunction* fun = &obj->as<JSFunction>();
-                RootedScript innerScript(cx, fun->getOrCreateScript(cx));
+                fun = &obj->as<JSFunction>();
+                innerScript = JSFunction::getOrCreateScript(cx, fun);
                 if (!innerScript)
                     return false;
 
                 if (!RemoveReferencedNames(cx, innerScript, remainingNames))
                     return false;
             }
         }
     }
@@ -3525,21 +3528,23 @@ AnalyzeEntrainedVariablesInScript(JSCont
             buf.putString(r.front());
         }
 
         printf("%s\n", buf.string());
     }
 
     if (innerScript->hasObjects()) {
         ObjectArray* objects = innerScript->objects();
+        RootedFunction fun(cx);
+        RootedScript innerInnerScript(cx);
         for (size_t i = 0; i < objects->length; i++) {
             JSObject* obj = objects->vector[i];
             if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
-                JSFunction* fun = &obj->as<JSFunction>();
-                RootedScript innerInnerScript(cx, fun->getOrCreateScript(cx));
+                fun = &obj->as<JSFunction>();
+                innerInnerScript = JSFunction::getOrCreateScript(cx, fun);
                 if (!innerInnerScript ||
                     !AnalyzeEntrainedVariablesInScript(cx, script, innerInnerScript))
                 {
                     return false;
                 }
             }
         }
     }
@@ -3560,21 +3565,23 @@ AnalyzeEntrainedVariablesInScript(JSCont
 // |bar| unnecessarily entrains |b|, and |baz| unnecessarily entrains |a|.
 bool
 js::AnalyzeEntrainedVariables(JSContext* cx, HandleScript script)
 {
     if (!script->hasObjects())
         return true;
 
     ObjectArray* objects = script->objects();
+    RootedFunction fun(cx);
+    RootedScript innerScript(cx);
     for (size_t i = 0; i < objects->length; i++) {
         JSObject* obj = objects->vector[i];
         if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted()) {
-            JSFunction* fun = &obj->as<JSFunction>();
-            RootedScript innerScript(cx, fun->getOrCreateScript(cx));
+            fun = &obj->as<JSFunction>();
+            innerScript = JSFunction::getOrCreateScript(cx, fun);
             if (!innerScript)
                 return false;
 
             if (script->functionDelazifying() && script->functionDelazifying()->needsCallObject()) {
                 if (!AnalyzeEntrainedVariablesInScript(cx, script, innerScript))
                     return false;
             }
 
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -830,17 +830,17 @@ class FastCallGuard
     }
 
     bool call(JSContext* cx, HandleValue callee, HandleValue thisv, MutableHandleValue rval) {
         args_.CallArgs::setCallee(callee);
         args_.CallArgs::setThis(thisv);
 
         if (useIon_ && fun_) {
             if (!script_) {
-                script_ = fun_->getOrCreateScript(cx);
+                script_ = JSFunction::getOrCreateScript(cx, fun_);
                 if (!script_)
                     return false;
             }
             MOZ_ASSERT(fun_->nonLazyScript() == script_);
 
             jit::MethodStatus status = jit::CanEnterUsingFastInvoke(cx, script_, args_.length());
             if (status == jit::Method_Error)
                 return false;
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -443,28 +443,28 @@ js::InternalCallOrConstruct(JSContext* c
         MOZ_ASSERT_IF(construct, !args.callee().constructHook());
         JSNative call = args.callee().callHook();
         if (!call)
             return ReportIsNotFunction(cx, args.calleev(), skipForCallee, construct);
         return CallJSNative(cx, call, args);
     }
 
     /* Invoke native functions. */
-    JSFunction* fun = &args.callee().as<JSFunction>();
+    RootedFunction fun(cx, &args.callee().as<JSFunction>());
     if (construct != CONSTRUCT && fun->isClassConstructor()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
         return false;
     }
 
     if (fun->isNative()) {
         MOZ_ASSERT_IF(construct, !fun->isConstructor());
         return CallJSNative(cx, fun->native(), args);
     }
 
-    if (!fun->getOrCreateScript(cx))
+    if (!JSFunction::getOrCreateScript(cx, fun))
         return false;
 
     /* Run function until JSOP_RETRVAL, JSOP_RETURN or error. */
     InvokeState state(cx, args, construct);
 
     // Check to see if createSingleton flag should be set for this frame.
     if (construct) {
         jsbytecode* pc;
@@ -2926,17 +2926,17 @@ CASE(JSOP_FUNCALL)
         TypeScript::Monitor(cx, script, REGS.pc, newsp[-1]);
         REGS.sp = newsp;
         ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
     }
 
     {
         MOZ_ASSERT(maybeFun);
         ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
-        ReservedRooted<JSScript*> funScript(&rootScript0, fun->getOrCreateScript(cx));
+        ReservedRooted<JSScript*> funScript(&rootScript0, JSFunction::getOrCreateScript(cx, fun));
         if (!funScript)
             goto error;
 
         bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, REGS.pc);
 
         TypeMonitorCall(cx, args, construct);
 
         mozilla::Maybe<InvokeState> state;
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -305,17 +305,17 @@ JSObject::splicePrototype(JSContext* cx,
 JSObject::makeLazyGroup(JSContext* cx, HandleObject obj)
 {
     MOZ_ASSERT(obj->hasLazyGroup());
     MOZ_ASSERT(cx->compartment() == obj->compartment());
 
     /* De-lazification of functions can GC, so we need to do it up here. */
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
         RootedFunction fun(cx, &obj->as<JSFunction>());
-        if (!fun->getOrCreateScript(cx))
+        if (!JSFunction::getOrCreateScript(cx, fun))
             return nullptr;
     }
 
     // Find flags which need to be specified immediately on the object.
     // Don't track whether singletons are packed.
     ObjectGroupFlags initialFlags = OBJECT_FLAG_SINGLETON | OBJECT_FLAG_NON_PACKED;
 
     if (obj->isIteratedSingleton())
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -3001,17 +3001,17 @@ JSRuntime::cloneSelfHostedFunctionScript
         return false;
     // JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
     // aren't any.
     MOZ_ASSERT(!sourceFun->isGenerator());
     MOZ_ASSERT(targetFun->isExtended());
     MOZ_ASSERT(targetFun->isInterpretedLazy());
     MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
 
-    RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
+    RootedScript sourceScript(cx, JSFunction::getOrCreateScript(cx, sourceFun));
     if (!sourceScript)
         return false;
 
     // Assert that there are no intervening scopes between the global scope
     // and the self-hosted script. Toplevel lexicals are explicitly forbidden
     // by the parser when parsing self-hosted code. The fact they have the
     // global lexical scope on the scope chain is for uniformity and engine
     // invariants.
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -331,17 +331,17 @@ InterpreterStack::pushInlineFrame(JSCont
 }
 
 MOZ_ALWAYS_INLINE bool
 InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
                                            HandleFunction callee, HandleValue newTarget,
                                            HandleObject envChain)
 {
     MOZ_ASSERT(callee->isGenerator());
-    RootedScript script(cx, callee->getOrCreateScript(cx));
+    RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
     InterpreterFrame* prev = regs.fp();
     jsbytecode* prevpc = regs.pc;
     Value* prevsp = regs.sp;
     MOZ_ASSERT(prev);
 
     script->ensureNonLazyCanonicalFunction(cx);
 
     LifoAlloc::Mark mark = allocator_.mark();
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3816,17 +3816,18 @@ TypeNewScript::maybeAnalyze(JSContext* c
     RootedObjectGroup groupRoot(cx, group);
     templateObject_ = NewObjectWithGroup<PlainObject>(cx, groupRoot, kind, TenuredObject);
     if (!templateObject_)
         return false;
 
     Vector<Initializer> initializerVector(cx);
 
     RootedPlainObject templateRoot(cx, templateObject());
-    if (!jit::AnalyzeNewScriptDefiniteProperties(cx, function(), group, templateRoot, &initializerVector))
+    RootedFunction fun(cx, function());
+    if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector))
         return false;
 
     if (!group->newScript())
         return true;
 
     MOZ_ASSERT(OnlyHasDataProperties(templateObject()->lastProperty()));
 
     if (templateObject()->slotSpan() != 0) {