diff options
author | Martok <martok@martoks-place.de> | 2023-04-11 03:02:33 +0200 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2023-05-01 17:16:21 +0200 |
commit | 7b74607f1fa0e93d00dc9261b6cd47d10324c92e (patch) | |
tree | f681a259d093dbcd65e6ccb67455ede16d1e02f3 /js | |
parent | 0f3f695117064813969f6fc29f92a69ff5cafb85 (diff) | |
download | uxp-7b74607f1fa0e93d00dc9261b6cd47d10324c92e.tar.gz |
Issue #2142 - Track isFieldInitializer on JSScript instead of Scope
Introduce a FunctionSyntaxKind for FieldInitializer since special rules
(around `arguments`) apply. At the same time we can move the flag from the
scope to the JSScript. This is similar to how derived constructors are handled
and makes the initWithEnclosingScope code closer to initWithEnclosingContext.
This version is a bit more complex than Mozilla's due to different storage of
bit flags on JSScript.
Based-on: m-c 1636800
Diffstat (limited to 'js')
-rw-r--r-- | js/src/frontend/ParseNode.h | 4 | ||||
-rw-r--r-- | js/src/frontend/Parser.cpp | 46 | ||||
-rw-r--r-- | js/src/frontend/Parser.h | 5 | ||||
-rw-r--r-- | js/src/frontend/SharedContext.h | 8 | ||||
-rw-r--r-- | js/src/jsfun.cpp | 13 | ||||
-rw-r--r-- | js/src/jsfun.h | 1 | ||||
-rw-r--r-- | js/src/jsscript.cpp | 7 | ||||
-rw-r--r-- | js/src/jsscript.h | 19 | ||||
-rw-r--r-- | js/src/vm/Scope.cpp | 13 | ||||
-rw-r--r-- | js/src/vm/Scope.h | 9 |
10 files changed, 77 insertions, 48 deletions
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 57a65a9e9b..4c9f1cc914 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -625,7 +625,8 @@ enum class FunctionSyntaxKind Expression, // A non-arrow function expression. Statement, // A named function appearing as a Statement. Arrow, - Method, // Method of a class or object. Field initializers also desugar to methods. + Method, // Method of a class or object. + FieldInitializer, // Field initializers desugar to methods. ClassConstructor, DerivedClassConstructor, Getter, @@ -659,6 +660,7 @@ static inline bool IsMethodDefinitionKind(FunctionSyntaxKind kind) { return kind == FunctionSyntaxKind::Method || + kind == FunctionSyntaxKind::FieldInitializer || IsConstructorKind(kind) || IsGetterKind(kind) || IsSetterKind(kind); } diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index c319924fa7..f69e3cf08a 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -221,7 +221,7 @@ SharedContext::computeAllowSyntax(Scope* scope) allowNewTarget_ = true; allowSuperProperty_ = fun->allowSuperProperty(); allowSuperCall_ = fun->isDerivedClassConstructor(); - if (funScope->isFieldInitializer()) { + if (fun->isFieldInitializer()) { allowSuperCall_ = false; allowArguments_ = false; } @@ -526,6 +526,11 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt allowNewTarget_ = true; allowSuperProperty_ = fun->allowSuperProperty(); + if (kind == FunctionSyntaxKind::FieldInitializer) { + setFieldInitializer(); + allowArguments_ = false; + } + if (IsConstructorKind(kind)) { auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>(); MOZ_ASSERT(stmt); @@ -556,13 +561,6 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt } void -FunctionBox::initFieldInitializer(ParseContext* enclosing) -{ - this->initWithEnclosingParseContext(enclosing, FunctionSyntaxKind::Method); - allowArguments_ = false; -} - -void FunctionBox::initWithEnclosingScope(Scope* enclosingScope) { if (!function()->isArrow()) { @@ -1883,8 +1881,7 @@ Parser<FullParseHandler>::newEvalScopeData(ParseContext::Scope& scope) template <> Maybe<FunctionScope::Data*> -Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs, - bool isFieldInitializer) +Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs) { Vector<BindingName> positionalFormals(context); Vector<BindingName> formals(context); @@ -1958,8 +1955,6 @@ Parser<FullParseHandler>::newFunctionScopeData(ParseContext::Scope& scope, bool if (!bindings) return Nothing(); - bindings->isFieldInitializer = isFieldInitializer; - // The ordering here is important. See comments in FunctionScope. BindingName* start = bindings->trailingNames.start(); BindingName* cursor = start; @@ -2408,8 +2403,7 @@ Parser<ParseHandler>::finishFunctionScopes(bool isStandaloneFunction) template <> bool -Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */, - bool isFieldInitializer /* = false */) +Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */) { if (!finishFunctionScopes(isStandaloneFunction)) return false; @@ -2426,8 +2420,7 @@ Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */ { Maybe<FunctionScope::Data*> bindings = newFunctionScopeData(pc->functionScope(), - hasParameterExprs, - isFieldInitializer); + hasParameterExprs); if (!bindings) return false; funbox->functionScopeBindings().set(*bindings); @@ -2445,8 +2438,7 @@ Parser<FullParseHandler>::finishFunction(bool isStandaloneFunction /* = false */ template <> bool -Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */, - bool isFieldInitializer /* = false */) +Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false */) { // The LazyScript for a lazily parsed function needs to know its set of // free variables and inner functions so that when it is fully parsed, we @@ -2816,6 +2808,7 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, allocKind = gc::AllocKind::FUNCTION_EXTENDED; break; case FunctionSyntaxKind::Method: + case FunctionSyntaxKind::FieldInitializer: MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator); flags = (generatorKind == NotGenerator && asyncKind == SyncFunction ? JSFunction::INTERPRETED_METHOD @@ -3056,6 +3049,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn bool duplicatedParam = false; bool disallowDuplicateParams = kind == FunctionSyntaxKind::Arrow || kind == FunctionSyntaxKind::Method || + kind == FunctionSyntaxKind::FieldInitializer || kind == FunctionSyntaxKind::ClassConstructor; AtomVector& positionalFormals = pc->positionalFormalParameterNames(); @@ -3614,7 +3608,11 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict syntaxKind = FunctionSyntaxKind::ClassConstructor; } } else if (fun->isMethod()) { - syntaxKind = FunctionSyntaxKind::Method; + if (fun->isFieldInitializer()) { + syntaxKind = FunctionSyntaxKind::FieldInitializer; + } else { + syntaxKind = FunctionSyntaxKind::Method; + } } else if (fun->isGetter()) { syntaxKind = FunctionSyntaxKind::Getter; } else if (fun->isSetter()) { @@ -7991,15 +7989,16 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& clas } // Create the anonymous function object. + FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::FieldInitializer; RootedFunction fun(context, - newFunction(nullptr, FunctionSyntaxKind::Method, + newFunction(nullptr, syntaxKind, GeneratorKind::NotGenerator, FunctionAsyncKind::SyncFunction)); if (!fun) return null(); // Create the top-level field initializer node. - FunctionNodeType funNode = handler.newFunction(FunctionSyntaxKind::Method, firstTokenPos); + FunctionNodeType funNode = handler.newFunction(syntaxKind, firstTokenPos); if (!funNode) return null(); @@ -8010,7 +8009,8 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& clas FunctionAsyncKind::SyncFunction, false); if (!funbox) return null(); - funbox->initFieldInitializer(pc); + funbox->initWithEnclosingParseContext(pc, syntaxKind); + MOZ_ASSERT(funbox->isFieldInitializer()); funbox->setStart(tokenStream, firstTokenPos); // Push a SourceParseContext on to the stack. @@ -8139,7 +8139,7 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& clas funbox->setNeedsHomeObject(); } - if (!finishFunction(false, true)) + if (!finishFunction()) return null(); if (!leaveInnerFunction(outerpc)) diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index ec6595b908..d0318e405d 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -1582,7 +1582,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) bool tryAnnexB, Directives inheritedDirectives, Directives* newDirectives); bool finishFunctionScopes(bool isStandaloneFunction); - bool finishFunction(bool isStandaloneFunction = false, bool isFieldInitializer = false); + bool finishFunction(bool isStandaloneFunction = false); bool leaveInnerFunction(ParseContext* outerpc); bool matchOrInsertSemicolonHelper(TokenStream::Modifier modifier); @@ -1630,8 +1630,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE) mozilla::Maybe<ModuleScope::Data*> newModuleScopeData(ParseContext::Scope& scope); mozilla::Maybe<EvalScope::Data*> newEvalScopeData(ParseContext::Scope& scope); mozilla::Maybe<FunctionScope::Data*> newFunctionScopeData(ParseContext::Scope& scope, - bool hasParameterExprs, - bool isFieldInitializer); + bool hasParameterExprs); mozilla::Maybe<VarScope::Data*> newVarScopeData(ParseContext::Scope& scope); mozilla::Maybe<LexicalScope::Data*> newLexicalScopeData(ParseContext::Scope& scope); LexicalScopeNodeType finishLexicalScope(ParseContext::Scope& scope, Node body); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 8aa068c1fc..4ac2da6fcd 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -155,6 +155,7 @@ class FunctionContextFlags bool needsHomeObject:1; bool isDerivedClassConstructor:1; + bool isFieldInitializer:1; // Whether this function has a .this binding. If true, we need to emit // JSOP_FUNCTIONTHIS in the prologue to initialize it. @@ -170,6 +171,7 @@ class FunctionContextFlags definitelyNeedsArgsObj(false), needsHomeObject(false), isDerivedClassConstructor(false), + isFieldInitializer(false), hasThisBinding(false), hasInnerFunctions(false) { } @@ -454,8 +456,7 @@ class FunctionBox : public ObjectBox, public SharedContext void initFromLazyFunction(); void initStandaloneFunction(Scope* enclosingScope); - void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind); - void initFieldInitializer(ParseContext* enclosing); + void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind); ObjectBox* toObjectBox() override { return this; } JSFunction* function() const { return &object->as<JSFunction>(); } @@ -537,6 +538,7 @@ class FunctionBox : public ObjectBox, public SharedContext bool needsHomeObject() const { return funCxFlags.needsHomeObject; } bool isDerivedClassConstructor() const { return funCxFlags.isDerivedClassConstructor; } bool hasInnerFunctions() const { return funCxFlags.hasInnerFunctions; } + bool isFieldInitializer() const { return funCxFlags.isFieldInitializer; } void setHasExtensibleScope() { funCxFlags.hasExtensibleScope = true; } void setHasThisBinding() { funCxFlags.hasThisBinding = true; } @@ -548,6 +550,8 @@ class FunctionBox : public ObjectBox, public SharedContext void setDerivedClassConstructor() { MOZ_ASSERT(function()->isClassConstructor()); funCxFlags.isDerivedClassConstructor = true; } void setHasInnerFunctions() { funCxFlags.hasInnerFunctions = true; } + void setFieldInitializer() { MOZ_ASSERT(function()->isMethod()); + funCxFlags.isFieldInitializer = true; } bool hasSimpleParameterList() const { return !hasRest() && !hasParameterExprs && !hasDestructuringArgs; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 2f3bd8ca55..67df78c2f1 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1286,6 +1286,19 @@ JSFunction::isDerivedClassConstructor() return derived; } +bool +JSFunction::isFieldInitializer() const +{ + bool init; + if (isInterpretedLazy()) { + init = lazyScript()->isFieldInitializer(); + } else { + init = nonLazyScript()->isFieldInitializer(); + } + MOZ_ASSERT_IF(init, isMethod()); + return init; +} + /* static */ bool JSFunction::getLength(JSContext* cx, HandleFunction fun, uint16_t* length) { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index ad6eb07a2c..1833aaeea5 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -595,6 +595,7 @@ class JSFunction : public js::NativeObject } bool isDerivedClassConstructor(); + bool isFieldInitializer() const; static unsigned offsetOfNativeOrScript() { static_assert(offsetof(U, n.native) == offsetof(U, i.s.script_), diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 1a148578a1..a3f5f07068 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -350,6 +350,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, NeedsHomeObject, IsDerivedClassConstructor, IsDefaultClassConstructor, + IsFieldInitializer, }; uint32_t length, lineno, column, nfixed, nslots; @@ -474,6 +475,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, scriptBits |= (1 << IsDerivedClassConstructor); if (script->isDefaultClassConstructor()) scriptBits |= (1 << IsDefaultClassConstructor); + if (script->isFieldInitializer()) + scriptBits |= (1 << IsFieldInitializer); } if (!xdr->codeUint32(&prologueLength)) @@ -620,6 +623,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, script->isDerivedClassConstructor_ = true; if (scriptBits & (1 << IsDefaultClassConstructor)) script->isDefaultClassConstructor_ = true; + if (scriptBits & (1 << IsFieldInitializer)) + script->isFieldInitializer_ = true; if (scriptBits & (1 << IsLegacyGenerator)) { MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator))); @@ -2807,6 +2812,7 @@ JSScript::initFromFunctionBox(ExclusiveContext* cx, HandleScript script, script->funHasExtensibleScope_ = funbox->hasExtensibleScope(); script->needsHomeObject_ = funbox->needsHomeObject(); script->isDerivedClassConstructor_ = funbox->isDerivedClassConstructor(); + script->isFieldInitializer_ = funbox->isFieldInitializer(); if (funbox->argumentsHasLocalBinding()) { script->setArgumentsHasVarBinding(); @@ -3485,6 +3491,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, dst->isGeneratorExp_ = src->isGeneratorExp(); dst->setGeneratorKind(src->generatorKind()); dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor(); + dst->isFieldInitializer_ = src->isFieldInitializer(); dst->needsHomeObject_ = src->needsHomeObject(); dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor(); dst->isAsync_ = src->asyncKind() == AsyncFunction; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 5534df5806..5d6c09dba6 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1120,6 +1120,8 @@ class JSScript : public js::gc::TenuredCell bool isDerivedClassConstructor_:1; bool isDefaultClassConstructor_:1; + bool isFieldInitializer_:1; + bool isAsync_:1; bool hasRest_:1; @@ -1129,7 +1131,10 @@ class JSScript : public js::gc::TenuredCell // instead of private to suppress -Wunused-private-field compiler warnings. protected: #if JS_BITS_PER_WORD == 32 - // Currently no padding is needed. +# ifndef DEBUG + // DEBUG is currently 4 bytes larger and doesn't need padding to gc::CellSize + uint32_t padding_; +# endif #endif // @@ -1458,6 +1463,10 @@ class JSScript : public js::gc::TenuredCell return isDerivedClassConstructor_; } + bool isFieldInitializer() const { + return isFieldInitializer_; + } + /* * As an optimization, even when argsHasLocalBinding, the function prologue * may not need to create an arguments object. This is determined by @@ -2096,6 +2105,7 @@ class LazyScript : public gc::TenuredCell uint32_t hasBeenCloned : 1; uint32_t treatAsRunOnce : 1; uint32_t isDerivedClassConstructor : 1; + uint32_t isFieldInitializer : 1; uint32_t needsHomeObject : 1; uint32_t hasRest : 1; uint32_t parseGoal : 1; @@ -2312,6 +2322,13 @@ class LazyScript : public gc::TenuredCell p_.isDerivedClassConstructor = true; } + bool isFieldInitializer() const { + return p_.isFieldInitializer; + } + void setIsFieldInitializer() { + p_.isFieldInitializer = true; + } + bool needsHomeObject() const { return p_.needsHomeObject; } diff --git a/js/src/vm/Scope.cpp b/js/src/vm/Scope.cpp index 870add219f..60d845836e 100644 --- a/js/src/vm/Scope.cpp +++ b/js/src/vm/Scope.cpp @@ -610,14 +610,12 @@ FunctionScope::create(ExclusiveContext* cx, Handle<Data*> dataArg, if (!data) return nullptr; - return createWithData(cx, &data, hasParameterExprs, dataArg ? dataArg->isFieldInitializer : false, - needsEnvironment, fun, enclosing); + return createWithData(cx, &data, hasParameterExprs, needsEnvironment, fun, enclosing); } /* static */ FunctionScope* FunctionScope::createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data, - bool hasParameterExprs, bool isFieldInitializer, - bool needsEnvironment, + bool hasParameterExprs, bool needsEnvironment, HandleFunction fun, HandleScope enclosing) { MOZ_ASSERT(data); @@ -638,7 +636,6 @@ FunctionScope::createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data return nullptr; } - data->isFieldInitializer = isFieldInitializer; data->hasParameterExprs = hasParameterExprs; data->canonicalFunction.init(fun); @@ -740,20 +737,16 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin uint8_t needsEnvironment; uint8_t hasParameterExprs; - uint8_t isFieldInitializer; uint32_t nextFrameSlot; if (mode == XDR_ENCODE) { needsEnvironment = scope->hasEnvironment(); hasParameterExprs = data->hasParameterExprs; - isFieldInitializer = data->isFieldInitializer; nextFrameSlot = data->nextFrameSlot; } if (!xdr->codeUint8(&needsEnvironment)) return false; if (!xdr->codeUint8(&hasParameterExprs)) return false; - if (!xdr->codeUint8(&isFieldInitializer)) - return false; if (!xdr->codeUint16(&data->nonPositionalFormalStart)) return false; if (!xdr->codeUint16(&data->varStart)) @@ -768,7 +761,7 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin MOZ_ASSERT(!data->nextFrameSlot); } - scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, !!isFieldInitializer, + scope.set(createWithData(cx, &uniqueData.ref(), hasParameterExprs, needsEnvironment, fun, enclosing)); if (!scope) return false; diff --git a/js/src/vm/Scope.h b/js/src/vm/Scope.h index a1e52e3800..b4e83dfc9c 100644 --- a/js/src/vm/Scope.h +++ b/js/src/vm/Scope.h @@ -500,9 +500,6 @@ class FunctionScope : public Scope // bindings. bool hasParameterExprs = false; - // Anonymous functions used in field initializers are limited. - bool isFieldInitializer = false; - // Bindings are sorted by kind in both frames and environments. // // Positional formal parameter names are those that are not @@ -551,7 +548,7 @@ class FunctionScope : public Scope private: static FunctionScope* createWithData(ExclusiveContext* cx, MutableHandle<UniquePtr<Data>> data, - bool hasParameterExprs, bool isFieldInitializer, + bool hasParameterExprs, bool needsEnvironment, HandleFunction fun, HandleScope enclosing); @@ -578,10 +575,6 @@ class FunctionScope : public Scope return data().hasParameterExprs; } - bool isFieldInitializer() const { - return data().isFieldInitializer; - } - uint32_t numPositionalFormalParameters() const { return data().nonPositionalFormalStart; } |