--- 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 {
Files
/js/src/frontend/CompilationStencil.h
/js/src/frontend/Stencil.cpp
Changesets
Diffs
/js/src/frontend/CompilationStencil.h
/js/src/frontend/Stencil.cpp