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(); MOZ_ASSERT(stmt); @@ -555,13 +560,6 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt } } -void -FunctionBox::initFieldInitializer(ParseContext* enclosing) -{ - this->initWithEnclosingParseContext(enclosing, FunctionSyntaxKind::Method); - allowArguments_ = false; -} - void FunctionBox::initWithEnclosingScope(Scope* enclosingScope) { @@ -1883,8 +1881,7 @@ Parser::newEvalScopeData(ParseContext::Scope& scope) template <> Maybe -Parser::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs, - bool isFieldInitializer) +Parser::newFunctionScopeData(ParseContext::Scope& scope, bool hasParameterExprs) { Vector positionalFormals(context); Vector formals(context); @@ -1958,8 +1955,6 @@ Parser::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::finishFunctionScopes(bool isStandaloneFunction) template <> bool -Parser::finishFunction(bool isStandaloneFunction /* = false */, - bool isFieldInitializer /* = false */) +Parser::finishFunction(bool isStandaloneFunction /* = false */) { if (!finishFunctionScopes(isStandaloneFunction)) return false; @@ -2426,8 +2420,7 @@ Parser::finishFunction(bool isStandaloneFunction /* = false */ { Maybe bindings = newFunctionScopeData(pc->functionScope(), - hasParameterExprs, - isFieldInitializer); + hasParameterExprs); if (!bindings) return false; funbox->functionScopeBindings().set(*bindings); @@ -2445,8 +2438,7 @@ Parser::finishFunction(bool isStandaloneFunction /* = false */ template <> bool -Parser::finishFunction(bool isStandaloneFunction /* = false */, - bool isFieldInitializer /* = false */) +Parser::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::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::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::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::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::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::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 newModuleScopeData(ParseContext::Scope& scope); mozilla::Maybe newEvalScopeData(ParseContext::Scope& scope); mozilla::Maybe newFunctionScopeData(ParseContext::Scope& scope, - bool hasParameterExprs, - bool isFieldInitializer); + bool hasParameterExprs); mozilla::Maybe newVarScopeData(ParseContext::Scope& scope); mozilla::Maybe 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(); } @@ -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* xdr, HandleScope scriptEnclosingScope, NeedsHomeObject, IsDerivedClassConstructor, IsDefaultClassConstructor, + IsFieldInitializer, }; uint32_t length, lineno, column, nfixed, nslots; @@ -474,6 +475,8 @@ js::XDRScript(XDRState* 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* 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 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> 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, MutableHandleisFieldInitializer = isFieldInitializer; data->hasParameterExprs = hasParameterExprs; data->canonicalFunction.init(fun); @@ -740,20 +737,16 @@ FunctionScope::XDR(XDRState* 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* 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> 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; }