arai-a / smoosh-sync

Automation to make jsparagus and SpiderMonkey bytecode in sync
2 stars 0 forks source link

/js/src/frontend/CompilationStencil.h and one more file have been updated (db6886fd) #328

Open github-actions[bot] opened 1 year ago

github-actions[bot] commented 1 year ago

Files

Changesets

Diffs

/js/src/frontend/CompilationStencil.h

--- 44753b3cb852aea36a82fb219e6ea6aaab868587/js/src/frontend/CompilationStencil.h
+++ 20edf5ff2283dfc74fdf23f9b6e2f5100c7354d4/js/src/frontend/CompilationStencil.h
@@ -59,39 +59,49 @@ namespace frontend {

 struct CompilationInput;
 struct CompilationStencil;
 struct CompilationGCOutput;
 class ScriptStencilIterable;
 struct InputName;
 class ScopeBindingCache;

+// When delazifying modules' inner functions, the actual global scope is used.
+// However, when doing a delazification the global scope is not available. We
+// use this dummy type to be a placeholder to be used as part of the InputScope
+// variants to mimic what the Global scope would be used for.
+struct FakeStencilGlobalScope {};
+
 // Reference to a Scope within a CompilationStencil.
 struct ScopeStencilRef {
   const CompilationStencil& context_;
   const ScopeIndex scopeIndex_;

   // Lookup the ScopeStencil referenced by this ScopeStencilRef.
   inline const ScopeStencil& scope() const;
 };

 // Wraps a scope for a CompilationInput. The scope is either as a GC pointer to
 // an instantiated scope, or as a reference to a CompilationStencil.
 //
 // Note: A scope reference may be nullptr/InvalidIndex if there is no such
 // scope, such as the enclosingScope at the end of a scope chain. See `isNull`
 // helper.
 class InputScope {
-  using InputScopeStorage = mozilla::Variant<Scope*, ScopeStencilRef>;
+  using InputScopeStorage =
+      mozilla::Variant<Scope*, ScopeStencilRef, FakeStencilGlobalScope>;
   InputScopeStorage scope_;

  public:
   // Create an InputScope given an instantiated scope.
   explicit InputScope(Scope* ptr) : scope_(ptr) {}

+  // Create an InputScope for a global.
+  explicit InputScope(FakeStencilGlobalScope global) : scope_(global) {}
+
   // Create an InputScope given a CompilationStencil and the ScopeIndex which is
   // an offset within the same CompilationStencil given as argument.
   InputScope(const CompilationStencil& context, ScopeIndex scopeIndex)
       : scope_(ScopeStencilRef{context, scopeIndex}) {}

   // Returns the variant used by the InputScope. This can be useful for complex
   // cases where the following accessors are not enough.
   const InputScopeStorage& variant() const { return scope_; }
@@ -120,71 +130,99 @@ class InputScope {
   template <typename Matcher>
   decltype(auto) match(Matcher&& matcher) & {
     return scope_.match(std::forward<Matcher>(matcher));
   }

   bool isNull() const {
     return scope_.match(
         [](const Scope* ptr) { return !ptr; },
-        [](const ScopeStencilRef& ref) { return !ref.scopeIndex_.isValid(); });
+        [](const ScopeStencilRef& ref) { return !ref.scopeIndex_.isValid(); },
+        [](const FakeStencilGlobalScope&) { return false; });
   }

   ScopeKind kind() const {
     return scope_.match(
         [](const Scope* ptr) { return ptr->kind(); },
-        [](const ScopeStencilRef& ref) { return ref.scope().kind(); });
+        [](const ScopeStencilRef& ref) { return ref.scope().kind(); },
+        [](const FakeStencilGlobalScope&) { return ScopeKind::Global; });
   };
   bool hasEnvironment() const {
-    return scope_.match([](const Scope* ptr) { return ptr->hasEnvironment(); },
-                        [](const ScopeStencilRef& ref) {
-                          return ref.scope().hasEnvironment();
-                        });
+    return scope_.match(
+        [](const Scope* ptr) { return ptr->hasEnvironment(); },
+        [](const ScopeStencilRef& ref) { return ref.scope().hasEnvironment(); },
+        [](const FakeStencilGlobalScope&) {
+          // See Scope::hasEnvironment
+          return true;
+        });
   };
   inline InputScope enclosing() const;
   bool hasOnChain(ScopeKind kind) const {
     return scope_.match(
         [=](const Scope* ptr) { return ptr->hasOnChain(kind); },
         [=](const ScopeStencilRef& ref) {
           ScopeStencilRef it = ref;
           while (true) {
             const ScopeStencil& scope = it.scope();
             if (scope.kind() == kind) {
               return true;
             }
+            if (scope.kind() == ScopeKind::Module &&
+                kind == ScopeKind::Global) {
+              return true;
+            }
             if (!scope.hasEnclosing()) {
               break;
             }
             new (&it) ScopeStencilRef{ref.context_, scope.enclosing()};
           }
           return false;
+        },
+        [=](const FakeStencilGlobalScope&) {
+          return kind == ScopeKind::Global;
         });
   }
   uint32_t environmentChainLength() const {
     return scope_.match(
         [](const Scope* ptr) { return ptr->environmentChainLength(); },
         [](const ScopeStencilRef& ref) {
           uint32_t length = 0;
           ScopeStencilRef it = ref;
           while (true) {
             const ScopeStencil& scope = it.scope();
             if (scope.hasEnvironment() &&
                 scope.kind() != ScopeKind::NonSyntactic) {
               length++;
             }
+            if (scope.kind() == ScopeKind::Module) {
+              // Stencil do not encode the Global scope, as it used to be
+              // assumed to already exists. As moving delazification off-thread,
+              // we need to materialize a fake-stencil version of the Global
+              // Scope.
+              MOZ_ASSERT(!scope.hasEnclosing());
+              length += js::ModuleScope::EnclosingEnvironmentChainLength;
+            }
             if (!scope.hasEnclosing()) {
               break;
             }
             new (&it) ScopeStencilRef{ref.context_, scope.enclosing()};
           }
           return length;
+        },
+        [=](const FakeStencilGlobalScope&) {
+          // Stencil-based delazification needs to calculate
+          // environmentChainLength where the global is not available.
+          //
+          // The FakeStencilGlobalScope is used to represent what the global
+          // would be if we had access to it while delazifying.
+          return uint32_t(js::ModuleScope::EnclosingEnvironmentChainLength);
         });
   }
   void trace(JSTracer* trc);
-  bool isStencil() const { return scope_.is<ScopeStencilRef>(); };
+  bool isStencil() const { return !scope_.is<Scope*>(); };

   // Various accessors which are valid only when the InputScope is a
   // FunctionScope. Some of these accessors are returning values associated with
   // the canonical function.
  private:
   inline FunctionFlags functionFlags() const;
   inline ImmutableScriptFlags immutableFlags() const;

@@ -353,16 +391,20 @@ struct InputName {

   InputName(Scope*, JSAtom* ptr) : variant_(ptr) {}
   InputName(const ScopeStencilRef& scope, TaggedParserAtomIndex index)
       : variant_(NameStencilRef{scope.context_, index}) {}
   InputName(BaseScript*, JSAtom* ptr) : variant_(ptr) {}
   InputName(const ScriptStencilRef& script, TaggedParserAtomIndex index)
       : variant_(NameStencilRef{script.context_, index}) {}

+  // Dummy for empty global.
+  InputName(const FakeStencilGlobalScope&, TaggedParserAtomIndex)
+      : variant_(static_cast<JSAtom*>(nullptr)) {}
+
   // The InputName is either from an instantiated name, or from another
   // CompilationStencil. This method interns the current name in the parser atom
   // table of a CompilationState, which has a corresponding CompilationInput.
   TaggedParserAtomIndex internInto(FrontendContext* fc,
                                    ParserAtomsTable& parserAtoms,
                                    CompilationAtomCache& atomCache);

   // Compare an InputName, which is not yet interned, with `other` is either an
@@ -1777,59 +1819,76 @@ InputScope InputScope::enclosing() const
       [](const Scope* ptr) {
         // This may return a nullptr Scope pointer.
         return InputScope(ptr->enclosing());
       },
       [](const ScopeStencilRef& ref) {
         if (ref.scope().hasEnclosing()) {
           return InputScope(ref.context_, ref.scope().enclosing());
         }
+        // The global scope is not known by the Stencil, while parsing inner
+        // functions from Stencils where they are known at the execution using
+        // the GlobalScope.
+        if (ref.scope().kind() == ScopeKind::Module) {
+          return InputScope(FakeStencilGlobalScope{});
+        }
         return InputScope(nullptr);
-      });
+      },
+      [](const FakeStencilGlobalScope&) { return InputScope(nullptr); });
 }

 FunctionFlags InputScope::functionFlags() const {
   return scope_.match(
       [](const Scope* ptr) {
         JSFunction* fun = ptr->as<FunctionScope>().canonicalFunction();
         return fun->flags();
       },
       [](const ScopeStencilRef& ref) {
         MOZ_ASSERT(ref.scope().isFunction());
         ScriptIndex scriptIndex = ref.scope().functionIndex();
         ScriptStencil& data = ref.context_.scriptData[scriptIndex];
         return data.functionFlags;
+      },
+      [](const FakeStencilGlobalScope&) -> FunctionFlags {
+        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No functionFlags on global.");
       });
 }

 ImmutableScriptFlags InputScope::immutableFlags() const {
   return scope_.match(
       [](const Scope* ptr) {
         JSFunction* fun = ptr->as<FunctionScope>().canonicalFunction();
         return fun->baseScript()->immutableFlags();
       },
       [](const ScopeStencilRef& ref) {
         MOZ_ASSERT(ref.scope().isFunction());
         ScriptIndex scriptIndex = ref.scope().functionIndex();
         ScriptStencilExtra& extra = ref.context_.scriptExtra[scriptIndex];
         return extra.immutableFlags;
+      },
+      [](const FakeStencilGlobalScope&) -> ImmutableScriptFlags {
+        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No immutableFlags on global.");
       });
 }

 MemberInitializers InputScope::getMemberInitializers() const {
   return scope_.match(
       [](const Scope* ptr) {
         JSFunction* fun = ptr->as<FunctionScope>().canonicalFunction();
         return fun->baseScript()->getMemberInitializers();
       },
       [](const ScopeStencilRef& ref) {
         MOZ_ASSERT(ref.scope().isFunction());
         ScriptIndex scriptIndex = ref.scope().functionIndex();
         ScriptStencilExtra& extra = ref.context_.scriptExtra[scriptIndex];
         return extra.memberInitializers();
+      },
+      [](const FakeStencilGlobalScope&) -> MemberInitializers {
+        MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
+            "No getMemberInitializers on global.");
       });
 }

 const ScriptStencil& ScriptStencilRef::scriptData() const {
   return context_.scriptData[scriptIndex_];
 }

 const ScriptStencilExtra& ScriptStencilRef::scriptExtra() const {

/js/src/frontend/Stencil.cpp

--- 44753b3cb852aea36a82fb219e6ea6aaab868587/js/src/frontend/Stencil.cpp
+++ 20edf5ff2283dfc74fdf23f9b6e2f5100c7354d4/js/src/frontend/Stencil.cpp
@@ -81,16 +81,20 @@ using namespace js::frontend;
 static js::BindingIter InputBindingIter(Scope* ptr) {
   return js::BindingIter(ptr);
 }

 static ParserBindingIter InputBindingIter(const ScopeStencilRef& ref) {
   return ParserBindingIter(ref);
 }

+static ParserBindingIter InputBindingIter(const FakeStencilGlobalScope&) {
+  MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No bindings on empty global.");
+}
+
 InputName InputScript::displayAtom() const {
   return script_.match(
       [](BaseScript* ptr) {
         return InputName(ptr, ptr->function()->displayAtom());
       },
       [](const ScriptStencilRef& ref) {
         return InputName(ref, ref.scriptData().functionAtom);
       });
@@ -260,16 +264,20 @@ void AssertBorrowingSpan(const SpanT& sp
 bool ScopeBindingCache::canCacheFor(Scope* ptr) {
   MOZ_CRASH("Unexpected scope chain type: Scope*");
 }

 bool ScopeBindingCache::canCacheFor(ScopeStencilRef ref) {
   MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
 }

+bool ScopeBindingCache::canCacheFor(const FakeStencilGlobalScope& ref) {
+  MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
+}
+
 BindingMap<JSAtom*>* ScopeBindingCache::createCacheFor(Scope* ptr) {
   MOZ_CRASH("Unexpected scope chain type: Scope*");
 }

 BindingMap<JSAtom*>* ScopeBindingCache::lookupScope(Scope* ptr,
                                                     CacheGeneration gen) {
   MOZ_CRASH("Unexpected scope chain type: Scope*");
 }
@@ -279,20 +287,34 @@ BindingMap<TaggedParserAtomIndex>* Scope
   MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
 }

 BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::lookupScope(
     ScopeStencilRef ref, CacheGeneration gen) {
   MOZ_CRASH("Unexpected scope chain type: ScopeStencilRef");
 }

+BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::createCacheFor(
+    const FakeStencilGlobalScope& ref) {
+  MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
+}
+
+BindingMap<TaggedParserAtomIndex>* ScopeBindingCache::lookupScope(
+    const FakeStencilGlobalScope& ref, CacheGeneration gen) {
+  MOZ_CRASH("Unexpected scope chain type: FakeStencilGlobalScope");
+}
+
 bool NoScopeBindingCache::canCacheFor(Scope* ptr) { return false; }

 bool NoScopeBindingCache::canCacheFor(ScopeStencilRef ref) { return false; }

+bool NoScopeBindingCache::canCacheFor(const FakeStencilGlobalScope& ref) {
+  return false;
+}
+
 bool RuntimeScopeBindingCache::canCacheFor(Scope* ptr) { return true; }

 BindingMap<JSAtom*>* RuntimeScopeBindingCache::createCacheFor(Scope* ptr) {
   BaseScopeData* dataPtr = ptr->rawData();
   BindingMap<JSAtom*> bindingCache;
   if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) {
     return nullptr;
   }
@@ -335,16 +357,44 @@ BindingMap<TaggedParserAtomIndex>* Stenc
   auto* dataPtr = ref.context_.scopeNames[ref.scopeIndex_];
   auto ptr = scopeMap.lookup(dataPtr);
   if (!ptr) {
     return nullptr;
   }
   return &ptr->value();
 }

+static AbstractBaseScopeData<TaggedParserAtomIndex>
+    moduleGlobalAbstractScopeData;
+
+bool StencilScopeBindingCache::canCacheFor(const FakeStencilGlobalScope& ref) {
+  return true;
+}
+
+BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::createCacheFor(
+    const FakeStencilGlobalScope& ref) {
+  auto* dataPtr = &moduleGlobalAbstractScopeData;
+  BindingMap<TaggedParserAtomIndex> bindingCache;
+  if (!scopeMap.putNew(dataPtr, std::move(bindingCache))) {
+    return nullptr;
+  }
+
+  return lookupScope(ref, 1);
+}
+
+BindingMap<TaggedParserAtomIndex>* StencilScopeBindingCache::lookupScope(
+    const FakeStencilGlobalScope& ref, CacheGeneration gen) {
+  auto* dataPtr = &moduleGlobalAbstractScopeData;
+  auto ptr = scopeMap.lookup(dataPtr);
+  if (!ptr) {
+    return nullptr;
+  }
+  return &ptr->value();
+}
+
 bool ScopeContext::init(FrontendContext* fc, CompilationInput& input,
                         ParserAtomsTable& parserAtoms,
                         ScopeBindingCache* scopeCache, InheritThis inheritThis,
                         JSObject* enclosingEnv) {
   // Record the scopeCache to be used while looking up NameLocation bindings.
   this->scopeCache = scopeCache;
   scopeCacheGen = scopeCache->getCurrentGeneration();

@@ -894,16 +944,21 @@ static bool IsPrivateField(ScopeStencilR
     // # character is not part of the allowed character of static strings.
     MOZ_ASSERT(content[0] != '#');
   }
 #endif

   return false;
 }

+static bool IsPrivateField(const FakeStencilGlobalScope&,
+                           TaggedParserAtomIndex) {
+  MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No private fields on empty global.");
+}
+
 bool ScopeContext::cachePrivateFieldsForEval(FrontendContext* fc,
                                              CompilationInput& input,
                                              JSObject* enclosingEnvironment,
                                              const InputScope& effectiveScope,
                                              ParserAtomsTable& parserAtoms) {
   effectiveScopePrivateFieldCache_.emplace();

   // We compute an environment coordinate relative to the effective scope
@@ -957,16 +1012,22 @@ bool ScopeContext::cachePrivateFieldsFor

 #ifdef DEBUG
 static bool NameIsOnEnvironment(FrontendContext* fc,
                                 ParserAtomsTable& parserAtoms,
                                 CompilationAtomCache& atomCache,
                                 InputScope& scope, TaggedParserAtomIndex name) {
   JSAtom* jsname = nullptr;
   return scope.match([&](auto& scope_ref) {
+    if (std::is_same_v<decltype(scope_ref), FakeStencilGlobalScope&>) {
+      // This condition is added to handle the FakeStencilGlobalScope which is
+      // used to emulate the global object when delazifying while executing, and
+      // which is not provided by the Stencil.
+      return true;
+    }
     for (auto bi = InputBindingIter(scope_ref); bi; bi++) {
       // If found, the name must already be on the environment or an import,
       // or else there is a bug in the closed-over name analysis in the
       // Parser.
       InputName binding(scope_ref, bi.name());
       if (binding.isEqualTo(fc, parserAtoms, atomCache, name, &jsname)) {
         BindingLocation::Kind kind = bi.location().kind();

@@ -4333,16 +4394,24 @@ struct DumpOptionsFields {

   void operator()(const char* name, const char* value) {
     if (value) {
       json.property(name, value);
       return;
     }
     json.nullProperty(name);
   }
+
+  void operator()(const char* name, JS::ConstUTF8CharsZ value) {
+    if (value) {
+      json.property(name, value.c_str());
+      return;
+    }
+    json.nullProperty(name);
+  }
 };

 static void DumpOptionsFields(js::JSONPrinter& json,
                               const JS::ReadOnlyCompileOptions& options) {
   struct DumpOptionsFields printer {
     json
   };
   options.dumpWith(printer);