Bug 1632286 - Make ImmutableFlags::HasNonSyntacticScope an input flag. r=tcampbell
authorcaroline <ccullen@mozilla.com>
Tue, 28 Apr 2020 14:27:00 +0000
changeset 526521 b1766549aa1d7296555910c05512bf64041d15e2
parent 526520 b989206ee3fc9b3275788f2a50bd2f300d51f805
child 526522 9555dcc88ac9fcc0486559a1cef6ff71dba3bb21
push id114319
push userccullen@mozilla.com
push dateTue, 28 Apr 2020 16:21:09 +0000
treeherderautoland@b1766549aa1d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1632286
milestone77.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 1632286 - Make ImmutableFlags::HasNonSyntacticScope an input flag. r=tcampbell Differential Revision: https://phabricator.services.mozilla.com/D72491
js/src/builtin/Eval.cpp
js/src/debugger/Frame.cpp
js/src/frontend/BCEScriptStencil.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/SharedContext.cpp
js/src/frontend/SharedContext.h
js/src/vm/CompilationAndEvaluation.cpp
js/src/vm/JSScript.cpp
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -306,16 +306,18 @@ static bool EvalKernel(JSContext* cx, Ha
     if (introducerFilename) {
       options.setFileAndLine(filename, 1);
       options.setIntroductionInfo(introducerFilename, "eval", lineno,
                                   maybeScript, pcOffset);
     } else {
       options.setFileAndLine("eval", 1);
       options.setIntroductionType("eval");
     }
+    options.setNonSyntacticScope(
+        enclosing->hasOnChain(ScopeKind::NonSyntactic));
 
     AutoStableStringChars linearChars(cx);
     if (!linearChars.initTwoByte(cx, linearStr)) {
       return false;
     }
 
     SourceText<char16_t> srcBuf;
 
@@ -406,16 +408,18 @@ bool js::DirectEvalStringFromIon(JSConte
     if (introducerFilename) {
       options.setFileAndLine(filename, 1);
       options.setIntroductionInfo(introducerFilename, "eval", lineno,
                                   callerScript, pcOffset);
     } else {
       options.setFileAndLine("eval", 1);
       options.setIntroductionType("eval");
     }
+    options.setNonSyntacticScope(
+        enclosing->hasOnChain(ScopeKind::NonSyntactic));
 
     AutoStableStringChars linearChars(cx);
     if (!linearChars.initTwoByte(cx, linearStr)) {
       return false;
     }
 
     SourceText<char16_t> srcBuf;
 
--- a/js/src/debugger/Frame.cpp
+++ b/js/src/debugger/Frame.cpp
@@ -981,16 +981,17 @@ static bool EvaluateInEnv(JSContext* cx,
       cx, frame && frame.hasScript() ? frame.script() : nullptr);
   RootedScript script(cx);
 
   ScopeKind scopeKind;
   if (IsGlobalLexicalEnvironment(env)) {
     scopeKind = ScopeKind::Global;
   } else {
     scopeKind = ScopeKind::NonSyntactic;
+    options.setNonSyntacticScope(true);
   }
 
   if (frame) {
     MOZ_ASSERT(scopeKind == ScopeKind::NonSyntactic);
     RootedScope scope(cx,
                       GlobalScope::createEmpty(cx, ScopeKind::NonSyntactic));
     if (!scope) {
       return false;
--- a/js/src/frontend/BCEScriptStencil.cpp
+++ b/js/src/frontend/BCEScriptStencil.cpp
@@ -21,20 +21,18 @@ BCEScriptStencil::BCEScriptStencil(Bytec
 }
 
 void BCEScriptStencil::init(BytecodeEmitter& bce,
                             UniquePtr<ImmutableScriptData> immutableData) {
   natoms = bce.perScriptData().atomIndices()->count();
 
   immutableFlags = bce.sc->immutableFlags();
 
-  // Update the flags generated by BCE.
-  immutableFlags.setFlag(
-      ImmutableFlags::HasNonSyntacticScope,
-      bce.outermostScope().hasOnChain(ScopeKind::NonSyntactic));
+  MOZ_ASSERT(bce.outermostScope().hasOnChain(ScopeKind::NonSyntactic) ==
+             immutableFlags.hasFlag(ImmutableFlags::HasNonSyntacticScope));
 
   gcThings = bce.perScriptData().gcThingList().stealGCThings();
 
   // Hand over the ImmutableScriptData instance generated by BCE.
   immutableScriptData = std::move(immutableData);
 
   // Update flags specific to functions.
   if (isFunction()) {
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -922,33 +922,16 @@ ModuleObject* frontend::CompileModule(JS
 }
 
 ModuleObject* frontend::CompileModule(JSContext* cx,
                                       const JS::ReadOnlyCompileOptions& options,
                                       SourceText<Utf8Unit>& srcBuf) {
   return CreateModule(cx, options, srcBuf);
 }
 
-static void CheckFlagsOnDelazification(uint32_t lazy, uint32_t nonLazy) {
-#ifdef DEBUG
-  // These flags are expect to be unset for lazy scripts and are only valid
-  // after a script has been compiled with the full parser.
-  //
-  // NOTE: Keep in sync with JSScript::relazify().
-  constexpr uint32_t NonLazyFlagsMask =
-      uint32_t(BaseScript::ImmutableFlags::HasNonSyntacticScope);
-
-  // These flags are expected to match between lazy and full parsing.
-  constexpr uint32_t MatchedFlagsMask = ~NonLazyFlagsMask;
-
-  MOZ_ASSERT((lazy & NonLazyFlagsMask) == 0);
-  MOZ_ASSERT((lazy & MatchedFlagsMask) == (nonLazy & MatchedFlagsMask));
-#endif  // DEBUG
-}
-
 template <typename Unit>
 static bool CompileLazyFunctionImpl(JSContext* cx, Handle<BaseScript*> lazy,
                                     const Unit* units, size_t length) {
   MOZ_ASSERT(cx->compartment() == lazy->compartment());
 
   // We can only compile functions whose parents have previously been
   // compiled, because compilation requires full information about the
   // function's immediately enclosing scope.
@@ -1002,30 +985,34 @@ static bool CompileLazyFunctionImpl(JSCo
                                     lazy->generatorKind(), lazy->asyncKind());
   if (!pn) {
     return false;
   }
   if (!parser.publishDeferredFunctions()) {
     return false;
   }
 
-  uint32_t lazyFlags = lazy->immutableFlags();
+  mozilla::DebugOnly<uint32_t> lazyFlags =
+      static_cast<uint32_t>(lazy->immutableFlags());
 
   BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->funbox(),
                       compilationInfo, BytecodeEmitter::LazyFunction);
   if (!bce.init(pn->pn_pos)) {
     return false;
   }
 
   if (!bce.emitFunctionScript(pn, BytecodeEmitter::TopLevelFunction::Yes)) {
     return false;
   }
 
-  CheckFlagsOnDelazification(lazyFlags,
-                             bce.getResultScript()->immutableFlags());
+  MOZ_ASSERT(lazyFlags == bce.getResultScript()->immutableFlags());
+  MOZ_ASSERT(bce.getResultScript()->outermostScope()->hasOnChain(
+                 ScopeKind::NonSyntactic) ==
+             bce.getResultScript()->immutableFlags().hasFlag(
+                 JSScript::ImmutableFlags::HasNonSyntacticScope));
 
   assertException.reset();
   return true;
 }
 
 bool frontend::CompileLazyFunction(JSContext* cx, Handle<BaseScript*> lazy,
                                    const char16_t* units, size_t length) {
   return CompileLazyFunctionImpl(cx, lazy, units, length);
--- a/js/src/frontend/SharedContext.cpp
+++ b/js/src/frontend/SharedContext.cpp
@@ -14,16 +14,51 @@
 #include "wasm/AsmJS.h"
 
 #include "frontend/ParseContext-inl.h"
 #include "vm/EnvironmentObject-inl.h"
 
 namespace js {
 namespace frontend {
 
+SharedContext::SharedContext(JSContext* cx, Kind kind,
+                             CompilationInfo& compilationInfo,
+                             Directives directives, SourceExtent extent,
+                             ImmutableScriptFlags immutableFlags)
+    : cx_(cx),
+      kind_(kind),
+      compilationInfo_(compilationInfo),
+      thisBinding_(ThisBinding::Global),
+      extent(extent),
+      allowNewTarget_(false),
+      allowSuperProperty_(false),
+      allowSuperCall_(false),
+      allowArguments_(true),
+      inWith_(false),
+      needsThisTDZChecks_(false),
+      localStrict(false),
+      hasExplicitUseStrict_(false),
+      immutableFlags_(immutableFlags) {
+  if (kind_ == Kind::FunctionBox) {
+    immutableFlags_.setFlag(ImmutableFlags::IsFunction);
+  } else if (kind_ == Kind::Module) {
+    MOZ_ASSERT(!compilationInfo.options.nonSyntacticScope);
+    immutableFlags_.setFlag(ImmutableFlags::IsModule);
+  } else if (kind_ == Kind::Eval) {
+    immutableFlags_.setFlag(ImmutableFlags::IsForEval);
+  } else {
+    MOZ_ASSERT(kind_ == Kind::Global);
+  }
+
+  immutableFlags_.setFlag(ImmutableFlags::Strict, directives.strict());
+
+  immutableFlags_.setFlag(ImmutableFlags::HasNonSyntacticScope,
+                          compilationInfo.options.nonSyntacticScope);
+}
+
 void SharedContext::computeAllowSyntax(Scope* scope) {
   for (ScopeIter si(scope); si; si++) {
     if (si.kind() == ScopeKind::Function) {
       FunctionScope* funScope = &si.scope()->as<FunctionScope>();
       JSFunction* fun = funScope->canonicalFunction();
       if (fun->isArrow()) {
         continue;
       }
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -145,43 +145,17 @@ class SharedContext {
 
   void computeAllowSyntax(Scope* scope);
   void computeInWith(Scope* scope);
   void computeThisBinding(Scope* scope);
 
  public:
   SharedContext(JSContext* cx, Kind kind, CompilationInfo& compilationInfo,
                 Directives directives, SourceExtent extent,
-                ImmutableScriptFlags immutableFlags = {})
-      : cx_(cx),
-        kind_(kind),
-        compilationInfo_(compilationInfo),
-        thisBinding_(ThisBinding::Global),
-        extent(extent),
-        allowNewTarget_(false),
-        allowSuperProperty_(false),
-        allowSuperCall_(false),
-        allowArguments_(true),
-        inWith_(false),
-        needsThisTDZChecks_(false),
-        localStrict(false),
-        hasExplicitUseStrict_(false),
-        immutableFlags_(immutableFlags) {
-    if (kind_ == Kind::FunctionBox) {
-      immutableFlags_.setFlag(ImmutableFlags::IsFunction);
-    } else if (kind_ == Kind::Module) {
-      immutableFlags_.setFlag(ImmutableFlags::IsModule);
-    } else if (kind_ == Kind::Eval) {
-      immutableFlags_.setFlag(ImmutableFlags::IsForEval);
-    } else {
-      MOZ_ASSERT(kind_ == Kind::Global);
-    }
-
-    immutableFlags_.setFlag(ImmutableFlags::Strict, directives.strict());
-  }
+                ImmutableScriptFlags immutableFlags = {});
 
   // If this is the outermost SharedContext, the Scope that encloses
   // it. Otherwise nullptr.
   virtual Scope* compilationEnclosingScope() const = 0;
 
   bool isFunctionBox() const { return kind_ == Kind::FunctionBox; }
   inline FunctionBox* asFunctionBox();
   bool isModuleContext() const { return kind_ == Kind::Module; }
--- a/js/src/vm/CompilationAndEvaluation.cpp
+++ b/js/src/vm/CompilationAndEvaluation.cpp
@@ -257,17 +257,17 @@ class FunctionCompiler {
   }
 
   template <typename Unit>
   inline MOZ_MUST_USE bool addFunctionBody(const SourceText<Unit>& srcBuf) {
     return funStr_.append(srcBuf.get(), srcBuf.length());
   }
 
   JSFunction* finish(HandleObjectVector envChain,
-                     const ReadOnlyCompileOptions& options) {
+                     const ReadOnlyCompileOptions& optionsArg) {
     if (!funStr_.append(FunctionConstructorFinalBrace)) {
       return nullptr;
     }
 
     size_t newLen = funStr_.length();
     UniqueTwoByteChars stolen(funStr_.stealChars());
     if (!stolen) {
       return nullptr;
@@ -297,16 +297,20 @@ class FunctionCompiler {
       return nullptr;
     }
 
     // Make sure the static scope chain matches up when we have a
     // non-syntactic scope.
     MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
                   enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
 
+    CompileOptions options(cx_, optionsArg);
+    options.setNonSyntacticScope(
+        enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
+
     if (!js::frontend::CompileStandaloneFunction(
             cx_, &fun, options, newSrcBuf, mozilla::Some(parameterListEnd_),
             enclosingScope)) {
       return nullptr;
     }
 
     // When the function name isn't a valid identifier, the generated function
     // source in srcBuf won't include the name, so name the function manually.
@@ -470,16 +474,17 @@ static bool EvaluateSourceBuffer(JSConte
   CompileOptions options(cx, optionsArg);
   MOZ_ASSERT(!cx->zone()->isAtomsZone());
   AssertHeapIsIdle();
   CHECK_THREAD(cx);
   cx->check(env);
   MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(env),
                 scopeKind == ScopeKind::NonSyntactic);
 
+  options.setNonSyntacticScope(scopeKind == ScopeKind::NonSyntactic);
   options.setIsRunOnce(true);
 
   RootedScript script(cx);
   {
     LifoAllocScope allocScope(&cx->tempLifoAlloc());
     frontend::CompilationInfo compilationInfo(cx, allocScope, options);
     if (!compilationInfo.init(cx)) {
       return false;
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -4022,22 +4022,16 @@ void JSScript::relazify(JSRuntime* rt) {
 
   // Release the bytecode and gcthings list.
   // NOTE: We clear the PrivateScriptData to nullptr. This is fine because we
   //       only allowed relazification (via AllowRelazify) if the original lazy
   //       script we compiled from had a nullptr PrivateScriptData.
   swapData(scriptData);
   freeSharedData();
 
-  // Clear flags that are only set by the BytecodeEmitter. This ensures that
-  // CheckFlagsOnDelazification is still valid on next compile.
-  //
-  // NOTE: Keep in sync with CheckFlagsOnDelazification.
-  clearFlag(ImmutableFlags::HasNonSyntacticScope);
-
   // We should not still be in any side-tables for the debugger or
   // code-coverage. The finalizer will not be able to clean them up once
   // bytecode is released. We check in JSFunction::maybeRelazify() for these
   // conditions before requesting relazification.
   MOZ_ASSERT(!coverage::IsLCovEnabled());
   MOZ_ASSERT(!hasScriptCounts());
   MOZ_ASSERT(!hasDebugScript());
 
@@ -4844,26 +4838,27 @@ static JSScript* CopyScriptImpl(JSContex
     return nullptr;
   }
 
   /* NB: Keep this in sync with XDRScript. */
 
   // Some embeddings are not careful to use ExposeObjectToActiveJS as needed.
   JS::AssertObjectIsNotGray(sourceObject);
 
+  ImmutableScriptFlags flags = src->immutableFlags();
+  flags.setFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
+                scopes[0]->hasOnChain(ScopeKind::NonSyntactic));
+
   // Create a new JSScript to fill in.
   RootedScript dst(cx, JSScript::Create(cx, functionOrGlobal, sourceObject,
-                                        src->extent(), src->immutableFlags()));
+                                        src->extent(), flags));
   if (!dst) {
     return nullptr;
   }
 
-  dst->setFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
-               scopes[0]->hasOnChain(ScopeKind::NonSyntactic));
-
   // Reset the mutable flags to request arguments analysis as needed.
   dst->resetArgsUsageAnalysis();
 
   // Clone the PrivateScriptData into dst
   if (!PrivateScriptData::Clone(cx, src, dst, scopes)) {
     return nullptr;
   }