Bug 1583816 - Store associated JSFunction directly in JSScript r=jandem
☠☠ backed out by bb56e5bd2203 ☠ ☠
authorTed Campbell <tcampbell@mozilla.com>
Mon, 30 Sep 2019 12:57:43 +0000
changeset 495663 2736f38dd2ce83b8711c0db304fcf6cf5b62f56f
parent 495662 c520d4083fa2a2a66f5a6dc14a4f810e0002bad6
child 495664 73734a2e8547b2cc72920c255b933183e70ee8ba
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)
reviewersjandem
bugs1583816
milestone71.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 1583816 - Store associated JSFunction directly in JSScript r=jandem For function JSScripts, store the JSFunction in the BaseScript functionOrGlobal field. This makes JSScript more consistent with the LazyScript behaviour. Differential Revision: https://phabricator.services.mozilla.com/D47070
js/src/frontend/BytecodeCompilation.h
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/vm/JSScript.cpp
js/src/vm/JSScript.h
--- a/js/src/frontend/BytecodeCompilation.h
+++ b/js/src/frontend/BytecodeCompilation.h
@@ -88,17 +88,18 @@ 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(uint32_t toStringStart,
+  MOZ_MUST_USE bool internalCreateScript(HandleObject functionOrGlobal,
+                                         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,20 +150,22 @@ 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(toStringStart, toStringEnd, len);
+    return info.internalCreateScript(global, toStringStart, toStringEnd, len);
   }
 
   MOZ_MUST_USE bool handleParseFailure(BytecodeCompiler& compiler,
                                        const Directives& newDirectives,
                                        TokenStreamPosition& startPosition);
 };
 
 template <typename Unit>
@@ -305,19 +307,20 @@ 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(toStringStart, toStringEnd,
+    return info.internalCreateScript(function, toStringStart, toStringEnd,
                                      sourceBuffer_.length());
   }
 };
 
 AutoFrontendTraceLog::AutoFrontendTraceLog(JSContext* cx,
                                            const TraceLoggerTextId id,
                                            const ErrorReporter& errorReporter)
 #ifdef JS_TRACE_LOGGING
@@ -446,21 +449,23 @@ 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(uint32_t toStringStart,
+bool BytecodeCompiler::internalCreateScript(HandleObject functionOrGlobal,
+                                            uint32_t toStringStart,
                                             uint32_t toStringEnd,
                                             uint32_t sourceBufferLength) {
-  script = JSScript::Create(cx, options, sourceObject, /* sourceStart = */ 0,
-                            sourceBufferLength, toStringStart, toStringEnd);
+  script = JSScript::Create(cx, functionOrGlobal, 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
@@ -666,17 +671,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, funbox->toStringStart,
+    if (!createFunctionScript(info, fun, funbox->toStringStart,
                               funbox->toStringEnd)) {
       return false;
     }
 
     if (!parser->publishDeferredItems()) {
       return false;
     }
 
@@ -749,18 +754,18 @@ JSScript* frontend::CompileGlobalBinASTS
   if (!sourceObj) {
     return nullptr;
   }
 
   if (!sourceObj->source()->setBinASTSourceCopy(cx, src, len)) {
     return nullptr;
   }
 
-  RootedScript script(cx,
-                      JSScript::Create(cx, options, sourceObj, 0, len, 0, len));
+  RootedScript script(cx, JSScript::Create(cx, cx->global(), options, sourceObj,
+                                           0, len, 0, len));
 
   if (!script) {
     return nullptr;
   }
 
   Directives directives(options.forceStrictMode());
   GlobalSharedContext globalsc(cx, ScopeKind::Global, directives,
                                options.extraWarningsOption);
@@ -1063,17 +1068,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, options, sourceObj, lazy->sourceStart(),
+      cx, JSScript::Create(cx, fun, 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, options, sourceObject, funbox->bufStart,
+        cx, JSScript::Create(cx, fun, 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.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -1133,18 +1133,22 @@ 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) {
-    script = JSScript::Create(cx, *options, sourceObject, sourceStart,
-                              sourceEnd, toStringStart, toStringEnd);
+    RootedObject functionOrGlobal(cx,
+                                  fun ? static_cast<JSObject*>(fun)
+                                      : static_cast<JSObject*>(cx->global()));
+    script =
+        JSScript::Create(cx, functionOrGlobal, *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;
@@ -3804,61 +3808,64 @@ 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 global, uint8_t* stubEntry,
+JSScript::JSScript(HandleObject functionOrGlobal, uint8_t* stubEntry,
                    HandleScriptSourceObject sourceObject, uint32_t sourceStart,
                    uint32_t sourceEnd, uint32_t toStringStart,
                    uint32_t toStringEnd)
-    : js::BaseScript(stubEntry, global, sourceObject, sourceStart, sourceEnd,
-                     toStringStart, toStringEnd) {}
+    : js::BaseScript(stubEntry, functionOrGlobal, sourceObject, sourceStart,
+                     sourceEnd, toStringStart, toStringEnd) {}
 
 /* static */
-JSScript* JSScript::New(JSContext* cx, HandleScriptSourceObject sourceObject,
+JSScript* JSScript::New(JSContext* cx, HandleObject functionOrGlobal,
+                        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(cx->global(), stubEntry, sourceObject, sourceStart, sourceEnd,
-               toStringStart, toStringEnd);
+      JSScript(functionOrGlobal, 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, const ReadOnlyCompileOptions& options,
+JSScript* JSScript::Create(JSContext* cx, HandleObject functionOrGlobal,
+                           const ReadOnlyCompileOptions& options,
                            HandleScriptSourceObject sourceObject,
                            uint32_t sourceStart, uint32_t sourceEnd,
                            uint32_t toStringStart, uint32_t toStringEnd) {
-  RootedScript script(cx, JSScript::New(cx, sourceObject, sourceStart,
-                                        sourceEnd, toStringStart, toStringEnd));
+  RootedScript script(
+      cx, JSScript::New(cx, functionOrGlobal, 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);
@@ -3875,20 +3882,21 @@ JSScript* JSScript::Create(JSContext* cx
   }
 
   return script;
 }
 
 /* static */ JSScript* JSScript::CreateFromLazy(JSContext* cx,
                                                 Handle<LazyScript*> lazy) {
   RootedScriptSourceObject sourceObject(cx, lazy->sourceObject());
-  RootedScript script(
-      cx,
-      JSScript::New(cx, sourceObject, lazy->sourceStart(), lazy->sourceEnd(),
-                    lazy->toStringStart(), lazy->toStringEnd()));
+  RootedObject fun(cx, lazy->functionNonDelazifying());
+  RootedScript script(cx,
+                      JSScript::New(cx, fun, sourceObject, lazy->sourceStart(),
+                                    lazy->sourceEnd(), lazy->toStringStart(),
+                                    lazy->toStringEnd()));
   if (!script) {
     return nullptr;
   }
 
   script->setFlag(MutableFlags::TrackRecordReplayProgress,
                   ShouldTrackRecordReplayProgress(script));
 
   if (coverage::IsLCovEnabled()) {
@@ -4592,16 +4600,17 @@ 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");
@@ -4614,20 +4623,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, options, sourceObject, src->sourceStart(),
-                           src->sourceEnd(), src->toStringStart(),
-                           src->toStringEnd()));
+  RootedScript dst(cx,
+                   JSScript::Create(cx, functionOrGlobal, 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();
@@ -4670,17 +4679,18 @@ 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;
   }
 
-  return detail::CopyScript(cx, src, sourceObject, &scopes);
+  RootedObject global(cx, cx->global());
+  return detail::CopyScript(cx, src, global, 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());
 
@@ -4708,17 +4718,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, sourceObject, &scopes));
+  RootedScript dst(cx, detail::CopyScript(cx, src, fun, 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,16 +86,17 @@ 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
 
 /*
@@ -2401,31 +2402,32 @@ 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,
+      JSContext* cx, js::HandleScript src, js::HandleObject functionOrGlobal,
       js::HandleScriptSourceObject sourceObject,
       js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
 
  private:
-  JSScript(js::HandleObject global, uint8_t* stubEntry,
+  JSScript(js::HandleObject functionOrGlobal, uint8_t* stubEntry,
            js::HandleScriptSourceObject sourceObject, uint32_t sourceStart,
            uint32_t sourceEnd, uint32_t toStringStart, uint32_t toStringend);
 
-  static JSScript* New(JSContext* cx, js::HandleScriptSourceObject sourceObject,
+  static JSScript* New(JSContext* cx, js::HandleObject functionOrGlobal,
+                       js::HandleScriptSourceObject sourceObject,
                        uint32_t sourceStart, uint32_t sourceEnd,
                        uint32_t toStringStart, uint32_t toStringEnd);
 
  public:
-  static JSScript* Create(JSContext* cx,
+  static JSScript* Create(JSContext* cx, js::HandleObject functionOrGlobal,
                           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);