зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1718102 - Abstract CompilationInput lazy fields behind accessors. r=arai
This change adds accessors to reach the `BaseScript* lazy` field as well as all information taken from it. The intent being that most information used from the BaseScript are taken out of the ScriptStencil and ScriptStencilExtra structures, and that we can later use these in-place where the lazy field is used. Differential Revision: https://phabricator.services.mozilla.com/D119106
This commit is contained in:
Родитель
27213e21b9
Коммит
7e30d9ee03
|
@ -1007,22 +1007,15 @@ static bool CompileLazyFunction(JSContext* cx, CompilationInput& input,
|
|||
const Unit* units, size_t length) {
|
||||
MOZ_ASSERT(input.source);
|
||||
|
||||
MOZ_ASSERT(cx->compartment() == input.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.
|
||||
MOZ_ASSERT(input.lazy->isReadyForDelazification());
|
||||
|
||||
AutoAssertReportedException assertException(cx);
|
||||
|
||||
Rooted<JSFunction*> fun(cx, input.lazy->function());
|
||||
Rooted<JSFunction*> fun(cx, input.function());
|
||||
|
||||
InheritThis inheritThis = fun->isArrow() ? InheritThis::Yes : InheritThis::No;
|
||||
|
||||
LifoAllocScope allocScope(&cx->tempLifoAlloc());
|
||||
CompilationState compilationState(cx, allocScope, input);
|
||||
compilationState.setFunctionKey(input.lazy);
|
||||
compilationState.setFunctionKey(input.extent());
|
||||
MOZ_ASSERT(!compilationState.isInitialStencil());
|
||||
if (!compilationState.init(cx, inheritThis)) {
|
||||
return false;
|
||||
|
@ -1037,8 +1030,8 @@ static bool CompileLazyFunction(JSContext* cx, CompilationInput& input,
|
|||
}
|
||||
|
||||
FunctionNode* pn = parser.standaloneLazyFunction(
|
||||
fun, input.lazy->toStringStart(), input.lazy->strict(),
|
||||
input.lazy->generatorKind(), input.lazy->asyncKind());
|
||||
fun, input.extent().toStringStart, input.strict(), input.generatorKind(),
|
||||
input.asyncKind());
|
||||
if (!pn) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1055,15 +1048,15 @@ static bool CompileLazyFunction(JSContext* cx, CompilationInput& input,
|
|||
|
||||
// NOTE: Only allow relazification if there was no lazy PrivateScriptData.
|
||||
// This excludes non-leaf functions and all script class constructors.
|
||||
bool hadLazyScriptData = input.lazy->hasPrivateScriptData();
|
||||
bool isRelazifiableAfterDelazify = input.lazy->isRelazifiableAfterDelazify();
|
||||
bool hadLazyScriptData = input.hasPrivateScriptData();
|
||||
bool isRelazifiableAfterDelazify = input.isRelazifiable();
|
||||
if (isRelazifiableAfterDelazify && !hadLazyScriptData) {
|
||||
compilationState.scriptData[CompilationStencil::TopLevelIndex]
|
||||
.setAllowRelazify();
|
||||
}
|
||||
|
||||
mozilla::DebugOnly<uint32_t> lazyFlags =
|
||||
static_cast<uint32_t>(input.lazy->immutableFlags());
|
||||
static_cast<uint32_t>(input.immutableFlags());
|
||||
|
||||
Rooted<CompilationGCOutput> gcOutput(cx);
|
||||
{
|
||||
|
@ -1129,7 +1122,7 @@ static bool DelazifyCanonicalScriptedFunctionImpl(JSContext* cx,
|
|||
.setSelfHostingMode(false);
|
||||
|
||||
Rooted<CompilationInput> input(cx, CompilationInput(options));
|
||||
input.get().initFromLazy(lazy, ss);
|
||||
input.get().initFromLazy(cx, lazy, ss);
|
||||
|
||||
return CompileLazyFunction(cx, input.get(), units.get(), sourceLength);
|
||||
}
|
||||
|
|
|
@ -210,7 +210,8 @@ struct CompilationAtomCache {
|
|||
};
|
||||
|
||||
// Input of the compilation, including source and enclosing context.
|
||||
struct CompilationInput {
|
||||
struct CompilationInput
|
||||
: public ImmutableScriptFlagsAccessors<CompilationInput> {
|
||||
enum class CompilationTarget {
|
||||
Global,
|
||||
SelfHosting,
|
||||
|
@ -226,8 +227,10 @@ struct CompilationInput {
|
|||
|
||||
CompilationAtomCache atomCache;
|
||||
|
||||
BaseScript* lazy = nullptr;
|
||||
private:
|
||||
BaseScript* lazy_ = nullptr;
|
||||
|
||||
public:
|
||||
RefPtr<ScriptSource> source;
|
||||
|
||||
// * If the target is Global, null.
|
||||
|
@ -303,11 +306,17 @@ struct CompilationInput {
|
|||
return true;
|
||||
}
|
||||
|
||||
void initFromLazy(BaseScript* lazyScript, ScriptSource* ss) {
|
||||
void initFromLazy(JSContext* cx, BaseScript* lazyScript, ScriptSource* ss) {
|
||||
MOZ_ASSERT(cx->compartment() == lazyScript->compartment());
|
||||
|
||||
// We can only compile functions whose parents have previously been
|
||||
// compiled, because compilation requires full information about the
|
||||
// function's immediately enclosing scope.
|
||||
MOZ_ASSERT(lazyScript->isReadyForDelazification());
|
||||
target = CompilationTarget::Delazification;
|
||||
lazy = lazyScript;
|
||||
lazy_ = lazyScript;
|
||||
source = ss;
|
||||
enclosingScope = lazy->function()->enclosingScope();
|
||||
enclosingScope = lazy_->function()->enclosingScope();
|
||||
}
|
||||
|
||||
// Returns true if enclosingScope field is provided to init* function,
|
||||
|
@ -327,6 +336,37 @@ struct CompilationInput {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// FullParseHandler needs a BaseScript to find the closed-over-binding index,
|
||||
// as well as to walk over the inner functions references with
|
||||
// skipLazyInnerFunctions.
|
||||
BaseScript* lazyOuterScript() {
|
||||
MOZ_ASSERT(isInitialStencil() == !lazy_);
|
||||
return lazy_;
|
||||
}
|
||||
|
||||
// When compiling a lazy function, this is needed to initialize the
|
||||
// FunctionBox as well as the CompilationState.
|
||||
JSFunction* function() { return lazy_->function(); }
|
||||
|
||||
// When compiling an inner function, we want to know the unique identifier
|
||||
// which identify a function. This is computed from the source extend.
|
||||
const SourceExtent& extent() const { return lazy_->extent(); }
|
||||
|
||||
// See `BaseScript::immutableFlags_`.
|
||||
ImmutableScriptFlags immutableFlags() const {
|
||||
return lazy_->immutableFlags();
|
||||
}
|
||||
|
||||
bool hasPrivateScriptData() const {
|
||||
// This is equivalent to: ngcthings != 0 || useMemberInitializers()
|
||||
// See BaseScript::CreateRawLazy.
|
||||
return lazy_->hasPrivateScriptData();
|
||||
}
|
||||
|
||||
// Whether this CompilationInput is parsing the top-level of a script, or
|
||||
// false if we are parsing an inner function.
|
||||
bool isInitialStencil() { return !lazy_; }
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
// Size of dynamic data. Note that GC data is counted by GC and not here. We
|
||||
|
@ -735,8 +775,8 @@ struct ExtensibleCompilationStencil {
|
|||
return *this;
|
||||
}
|
||||
|
||||
void setFunctionKey(BaseScript* lazy) {
|
||||
functionKey = CompilationStencil::toFunctionKey(lazy->extent());
|
||||
void setFunctionKey(const SourceExtent& extent) {
|
||||
functionKey = CompilationStencil::toFunctionKey(extent);
|
||||
}
|
||||
|
||||
bool isInitialStencil() const {
|
||||
|
|
|
@ -174,7 +174,8 @@ NameLocation EmitterScope::searchAndCache(BytecodeEmitter* bce,
|
|||
// If the name is not found in the current compilation, walk the Scope
|
||||
// chain encompassing the compilation.
|
||||
if (!loc) {
|
||||
MOZ_ASSERT(bce->compilationState.input.lazy ||
|
||||
MOZ_ASSERT(bce->compilationState.input.target ==
|
||||
CompilationInput::CompilationTarget::Delazification ||
|
||||
bce->compilationState.input.target ==
|
||||
CompilationInput::CompilationTarget::Eval);
|
||||
inCurrentScript = false;
|
||||
|
|
|
@ -199,10 +199,10 @@ PerHandlerParser<ParseHandler>::PerHandlerParser(
|
|||
CompilationState& compilationState, void* internalSyntaxParser)
|
||||
: ParserBase(cx, options, foldConstants, compilationState),
|
||||
handler_(cx, compilationState.allocScope.alloc(),
|
||||
compilationState.input.lazy),
|
||||
compilationState.input.lazyOuterScript()),
|
||||
internalSyntaxParser_(internalSyntaxParser) {
|
||||
MOZ_ASSERT(compilationState.isInitialStencil() ==
|
||||
!compilationState.input.lazy);
|
||||
compilationState.input.isInitialStencil());
|
||||
}
|
||||
|
||||
template <class ParseHandler, typename Unit>
|
||||
|
|
|
@ -642,7 +642,7 @@ bool CompilationInput::initForStandaloneFunctionInNonSyntacticScope(
|
|||
|
||||
void CompilationInput::trace(JSTracer* trc) {
|
||||
atomCache.trace(trc);
|
||||
TraceNullableRoot(trc, &lazy, "compilation-input-lazy");
|
||||
TraceNullableRoot(trc, &lazy_, "compilation-input-lazy");
|
||||
TraceNullableRoot(trc, &enclosingScope, "compilation-input-enclosing-scope");
|
||||
}
|
||||
|
||||
|
@ -1131,8 +1131,8 @@ static bool InstantiateTopLevel(JSContext* cx, CompilationInput& input,
|
|||
MOZ_ASSERT(stencil.sharedData.get(CompilationStencil::TopLevelIndex));
|
||||
|
||||
if (!stencil.isInitialStencil()) {
|
||||
MOZ_ASSERT(input.lazy);
|
||||
RootedScript script(cx, JSScript::CastFromLazy(input.lazy));
|
||||
MOZ_ASSERT(input.lazyOuterScript());
|
||||
RootedScript script(cx, JSScript::CastFromLazy(input.lazyOuterScript()));
|
||||
if (!JSScript::fullyInitFromStencil(cx, input, stencil, gcOutput, script,
|
||||
CompilationStencil::TopLevelIndex)) {
|
||||
return false;
|
||||
|
@ -1325,9 +1325,9 @@ static void AssertDelazificationFieldsMatch(const CompilationStencil& stencil,
|
|||
static void FunctionsFromExistingLazy(CompilationInput& input,
|
||||
CompilationGCOutput& gcOutput) {
|
||||
MOZ_ASSERT(gcOutput.functions.empty());
|
||||
gcOutput.functions.infallibleAppend(input.lazy->function());
|
||||
gcOutput.functions.infallibleAppend(input.function());
|
||||
|
||||
for (JS::GCCellPtr elem : input.lazy->gcthings()) {
|
||||
for (JS::GCCellPtr elem : input.lazyOuterScript()->gcthings()) {
|
||||
if (!elem.is<JSObject>()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1355,7 +1355,7 @@ bool CompilationStencil::instantiateStencilAfterPreparation(
|
|||
// Distinguish between the initial (possibly lazy) compile and any subsequent
|
||||
// delazification compiles. Delazification will update existing GC things.
|
||||
bool isInitialParse = stencil.isInitialStencil();
|
||||
MOZ_ASSERT(stencil.isInitialStencil() == !input.lazy);
|
||||
MOZ_ASSERT(stencil.isInitialStencil() == input.isInitialStencil());
|
||||
|
||||
// Phase 1: Instantate JSAtoms.
|
||||
if (!InstantiateAtoms(cx, input, stencil)) {
|
||||
|
@ -1392,7 +1392,7 @@ bool CompilationStencil::instantiateStencilAfterPreparation(
|
|||
// specific lazy script. It is not used by instantiation, but we should
|
||||
// ensure it is correctly defined.
|
||||
MOZ_ASSERT(stencil.functionKey ==
|
||||
CompilationStencil::toFunctionKey(input.lazy->extent()));
|
||||
CompilationStencil::toFunctionKey(input.extent()));
|
||||
|
||||
FunctionsFromExistingLazy(input, gcOutput);
|
||||
MOZ_ASSERT(gcOutput.functions.length() == stencil.scriptData.size());
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "vm/BytecodeIterator.h"
|
||||
#include "vm/BytecodeLocation.h"
|
||||
#include "vm/BytecodeUtil.h"
|
||||
#include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind
|
||||
#include "vm/JSAtom.h"
|
||||
#include "vm/NativeObject.h"
|
||||
#include "vm/ScopeKind.h" // ScopeKind
|
||||
|
@ -1568,7 +1567,7 @@ class BaseScript : public gc::TenuredCellWithNonGCPointer<uint8_t>,
|
|||
}
|
||||
uint32_t toStringStart() const { return extent_.toStringStart; }
|
||||
uint32_t toStringEnd() const { return extent_.toStringEnd; }
|
||||
SourceExtent extent() const { return extent_; }
|
||||
const SourceExtent& extent() const { return extent_; }
|
||||
|
||||
[[nodiscard]] bool appendSourceDataForToString(JSContext* cx,
|
||||
js::StringBuffer& buf);
|
||||
|
@ -1581,16 +1580,6 @@ class BaseScript : public gc::TenuredCellWithNonGCPointer<uint8_t>,
|
|||
const MutableScriptFlags& mutableFlags() const { return mutableFlags_; }
|
||||
MutableScriptFlags& mutableFlags() { return mutableFlags_; }
|
||||
|
||||
GeneratorKind generatorKind() const {
|
||||
return isGenerator() ? GeneratorKind::Generator
|
||||
: GeneratorKind::NotGenerator;
|
||||
}
|
||||
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? FunctionAsyncKind::AsyncFunction
|
||||
: FunctionAsyncKind::SyncFunction;
|
||||
}
|
||||
|
||||
bool hasEnclosingScript() const { return warmUpData_.isEnclosingScript(); }
|
||||
BaseScript* enclosingScript() const {
|
||||
return warmUpData_.toEnclosingScript();
|
||||
|
@ -1698,24 +1687,6 @@ class BaseScript : public gc::TenuredCellWithNonGCPointer<uint8_t>,
|
|||
static constexpr size_t offsetOfWarmUpData() {
|
||||
return offsetof(BaseScript, warmUpData_);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isRelazifiableImpl() const {
|
||||
// A script may not be relazifiable if parts of it can be entrained in
|
||||
// interesting ways:
|
||||
// - Scripts with inner-functions or direct-eval (which can add
|
||||
// inner-functions) should not be relazified as their Scopes may be part
|
||||
// of another scope-chain.
|
||||
// - Generators and async functions may be re-entered in complex ways so
|
||||
// don't discard bytecode. The JIT resume code assumes this.
|
||||
// - Functions with template literals must always return the same object
|
||||
// instance so must not discard it by relazifying.
|
||||
return !hasInnerFunctions() && !hasDirectEval() && !isGenerator() &&
|
||||
!isAsync() && !hasCallSiteObj();
|
||||
}
|
||||
|
||||
public:
|
||||
bool isRelazifiableAfterDelazify() const { return isRelazifiableImpl(); }
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1941,8 +1912,6 @@ class JSScript : public js::BaseScript {
|
|||
|
||||
void updateJitCodeRaw(JSRuntime* rt);
|
||||
|
||||
bool isRelazifiable() const { return isRelazifiableImpl(); }
|
||||
|
||||
js::ModuleObject* module() const;
|
||||
|
||||
bool isGlobalCode() const;
|
||||
|
|
|
@ -22,11 +22,12 @@
|
|||
#include "frontend/SourceNotes.h" // js::SrcNote
|
||||
#include "frontend/TypedIndex.h" // js::frontend::TypedIndex
|
||||
|
||||
#include "js/AllocPolicy.h" // js::SystemAllocPolicy
|
||||
#include "js/TypeDecls.h" // JSContext,jsbytecode
|
||||
#include "js/UniquePtr.h" // js::UniquePtr
|
||||
#include "util/EnumFlags.h" // js::EnumFlags
|
||||
#include "util/TrailingArray.h" // js::TrailingArray
|
||||
#include "js/AllocPolicy.h" // js::SystemAllocPolicy
|
||||
#include "js/TypeDecls.h" // JSContext,jsbytecode
|
||||
#include "js/UniquePtr.h" // js::UniquePtr
|
||||
#include "util/EnumFlags.h" // js::EnumFlags
|
||||
#include "util/TrailingArray.h" // js::TrailingArray
|
||||
#include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind
|
||||
#include "vm/StencilEnums.h" // js::{TryNoteKind,ImmutableScriptFlagsEnum,MutableScriptFlagsEnum}
|
||||
|
||||
//
|
||||
|
@ -290,6 +291,30 @@ struct ImmutableScriptFlagsAccessors {
|
|||
|
||||
#undef IMMUTABLE_FLAG_GETTER
|
||||
#undef FLAG_GETTER
|
||||
|
||||
GeneratorKind generatorKind() const {
|
||||
return isGenerator() ? GeneratorKind::Generator
|
||||
: GeneratorKind::NotGenerator;
|
||||
}
|
||||
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? FunctionAsyncKind::AsyncFunction
|
||||
: FunctionAsyncKind::SyncFunction;
|
||||
}
|
||||
|
||||
bool isRelazifiable() const {
|
||||
// A script may not be relazifiable if parts of it can be entrained in
|
||||
// interesting ways:
|
||||
// - Scripts with inner-functions or direct-eval (which can add
|
||||
// inner-functions) should not be relazified as their Scopes may be part
|
||||
// of another scope-chain.
|
||||
// - Generators and async functions may be re-entered in complex ways so
|
||||
// don't discard bytecode. The JIT resume code assumes this.
|
||||
// - Functions with template literals must always return the same object
|
||||
// instance so must not discard it by relazifying.
|
||||
return !hasInnerFunctions() && !hasDirectEval() && !isGenerator() &&
|
||||
!isAsync() && !hasCallSiteObj();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Holder>
|
||||
|
|
Загрузка…
Ссылка в новой задаче