From bcb6203e4fe6b33580f1c4fd394032e771703162 Mon Sep 17 00:00:00 2001 From: Martok Date: Sun, 9 Apr 2023 19:54:45 +0200 Subject: [PATCH] Issue #2142 - Fix several scoping issues in field initializers Based-on: m-c 1540789, 1547130, 1547467 --- js/src/builtin/ReflectParse.cpp | 2 + js/src/frontend/BytecodeEmitter.cpp | 112 +++++++++++------------ js/src/frontend/BytecodeEmitter.h | 3 +- js/src/frontend/FullParseHandler.h | 32 ++++--- js/src/frontend/FunctionEmitter.cpp | 9 +- js/src/frontend/ObjectEmitter.cpp | 14 +-- js/src/frontend/ObjectEmitter.h | 16 ++-- js/src/frontend/ParseNode.h | 10 +-- js/src/frontend/Parser.cpp | 128 +++++++++++++-------------- js/src/frontend/SyntaxParseHandler.h | 5 +- js/src/vm/CommonPropertyNames.h | 1 - 11 files changed, 156 insertions(+), 176 deletions(-) diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index 242a4b8b0f..2b885574da 100644 --- a/js/src/builtin/ReflectParse.cpp +++ b/js/src/builtin/ReflectParse.cpp @@ -2701,6 +2701,8 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) return false; for (ParseNode* item : memberList->contents()) { + if (item->is()) + item = item->as().scopeBody(); if (item->is()) { ClassField* field = &item->as(); MOZ_ASSERT(memberList->pn_pos.encloses(field->pn_pos)); diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 5fb9ec7809..9932a63b58 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -2324,7 +2324,7 @@ BytecodeEmitter::emitSetThis(BinaryNode* setThisNode) return false; } - if (!emitInitializeInstanceFields(true)) { + if (!emitInitializeInstanceFields()) { return false; } @@ -7623,6 +7623,13 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy continue; } + if (propdef->is()) { + // Constructors are sometimes wrapped in LexicalScopeNodes. As we already + // handled emitting the constructor, skip it. + MOZ_ASSERT(propdef->as().scopeBody()->isKind(PNK_CLASSMETHOD)); + continue; + } + // Handle __proto__: v specially because *only* this form, and no other // involving "__proto__", performs [[Prototype]] mutation. if (propdef->isKind(PNK_MUTATEPROTO)) { @@ -7854,14 +7861,7 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy } } - if (obj->getKind() == PNK_CLASSMEMBERLIST) { - if (!emitCreateFieldKeys(obj)) - return false; - if (!emitCreateFieldInitializers(obj)) - return false; - } - - return true; + return true; } FieldInitializers @@ -8063,38 +8063,7 @@ BytecodeEmitter::findFieldInitializersForCall() } bool -BytecodeEmitter::emitCopyInitializersToLocalInitializers() -{ - MOZ_ASSERT(sc->asFunctionBox()->isDerivedClassConstructor()); - if (getFieldInitializers().numFieldInitializers == 0) - return true; - - NameOpEmitter noe(this, cx->names().dotLocalInitializers, NameOpEmitter::Kind::Initialize); - if (!noe.prepareForRhs()) { - // [stack] - return false; - } - - if (!emitGetName(cx->names().dotInitializers)) { - // [stack] .initializers - return false; - } - - if (!noe.emitAssignment()) { - // [stack] .initializers - return false; - } - - if (!emit1(JSOP_POP)) { - // [stack] - return false; - } - - return true; -} - -bool -BytecodeEmitter::emitInitializeInstanceFields(bool isSuperCall) +BytecodeEmitter::emitInitializeInstanceFields() { const FieldInitializers& fieldInitializers = findFieldInitializersForCall(); size_t numFields = fieldInitializers.numFieldInitializers; @@ -8103,16 +8072,9 @@ BytecodeEmitter::emitInitializeInstanceFields(bool isSuperCall) return true; } - if (isSuperCall) { - if (!emitGetName(cx->names().dotLocalInitializers)) { - // [stack] ARRAY - return false; - } - } else { - if (!emitGetName(cx->names().dotInitializers)) { - // [stack] ARRAY - return false; - } + if (!emitGetName(cx->names().dotInitializers)) { + // [stack] ARRAY + return false; } for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) { @@ -8625,16 +8587,19 @@ BytecodeEmitter::emitClass(ClassNode* classNode) ParseNode* heritageExpression = classNode->heritage(); ListNode* classMembers = classNode->memberList(); - FunctionNode* constructor = nullptr; - for (ParseNode* mn : classMembers->contents()) { - if (mn->is()) { - ClassMethod& method = mn->as(); + ParseNode* constructor = nullptr; + for (ParseNode* classElement : classMembers->contents()) { + ParseNode* unwrappedElement = classElement; + if (unwrappedElement->is()) + unwrappedElement = unwrappedElement->as().scopeBody(); + if (unwrappedElement->is()) { + ClassMethod& method = unwrappedElement->as(); ParseNode& methodName = method.name(); if (!method.isStatic() && (methodName.isKind(PNK_OBJECT_PROPERTY_NAME) || methodName.isKind(PNK_STRING)) && methodName.as().atom() == cx->names().constructor) { - constructor = &method.method(); + constructor = classElement; break; } } @@ -8656,8 +8621,8 @@ BytecodeEmitter::emitClass(ClassNode* classNode) } } - if (!classNode->isEmptyScope()) { - if (!ce.emitScope(classNode->scopeBindings(), classNode->names() != nullptr)) { + if (LexicalScopeNode* scopeBindings = classNode->scopeBindings()) { + if (!ce.emitScope(scopeBindings->scopeBindings())) { // [stack] return false; } @@ -8685,12 +8650,35 @@ BytecodeEmitter::emitClass(ClassNode* classNode) } if (constructor) { - bool needsHomeObject = constructor->funbox()->needsHomeObject(); + FunctionNode* ctor; + // .fieldKeys must be declared outside the scope .initializers is declared + // in, hence this extra scope. + Maybe lse; + if (constructor->is()) { + lse.emplace(this); + if (!lse->emitScope(ScopeKind::Lexical, constructor->as().scopeBindings())) + return false; + + // Any class with field initializers will have a constructor + if (!emitCreateFieldInitializers(classMembers)) + return false; + ctor = &constructor->as().scopeBody()->as().method(); + } else { + ctor = &constructor->as().method(); + } + + bool needsHomeObject = ctor->funbox()->needsHomeObject(); // HERITAGE is consumed inside emitFunction. - if (!emitFunction(constructor, isDerived, classMembers)) { + if (!emitFunction(ctor, isDerived, classMembers)) { // [stack] HOMEOBJ CTOR return false; } + if (lse.isSome()) { + if (!lse->emitEnd()) { + return false; + } + lse.reset(); + } if (!ce.emitInitConstructor(needsHomeObject)) { // [stack] CTOR HOMEOBJ return false; @@ -8706,6 +8694,10 @@ BytecodeEmitter::emitClass(ClassNode* classNode) // [stack] CTOR HOMEOBJ return false; } + + if (!emitCreateFieldKeys(classMembers)) + return false; + if (!ce.emitEnd(kind)) { // [stack] # class declaration // [stack] diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 88594778b6..95e28f213a 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -533,8 +533,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj); MOZ_MUST_USE bool emitCreateFieldInitializers(ListNode* obj); const FieldInitializers& findFieldInitializersForCall(); - MOZ_MUST_USE bool emitCopyInitializersToLocalInitializers(); - MOZ_MUST_USE bool emitInitializeInstanceFields(bool isSuperCall); + MOZ_MUST_USE bool emitInitializeInstanceFields(); // To catch accidental misuse, emitUint16Operand/emit3 assert that they are // not used to unconditionally emit JSOP_GETLOCAL. Variable access should diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index d8ac80e2c6..345fd483a8 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -459,31 +459,35 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) return true; } - MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType memberList, Node key, FunctionNodeType funNode, - JSOp op, bool isStatic) + MOZ_MUST_USE ClassMethod* newClassMethodDefinition(Node key, FunctionNodeType funNode, + JSOp op, bool isStatic) { - MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST)); MOZ_ASSERT(isUsableAsObjectPropertyName(key)); - ClassMethod* classMethod = new_(key, funNode, op, isStatic); - if (!classMethod) - return false; - memberList->append(classMethod); - return true; + return new_(key, funNode, op, isStatic); } - MOZ_MUST_USE bool addClassFieldDefinition(ListNodeType memberList, Node name, FunctionNodeType initializer) + MOZ_MUST_USE ClassField* newClassFieldDefinition(Node name, FunctionNodeType initializer) { - MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST)); MOZ_ASSERT(isUsableAsObjectPropertyName(name)); - ParseNode* classField = new_(name, initializer); - if (!classField) - return false; - memberList->append(classField); + return new_(name, initializer); + } + + MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member) + { + MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST)); + // Constructors can be surrounded by LexicalScopes. + MOZ_ASSERT(member->isKind(PNK_CLASSMETHOD) || + member->isKind(PNK_CLASSFIELD) || + (member->isKind(PNK_LEXICALSCOPE) && + member->as().scopeBody()->isKind(PNK_CLASSMETHOD))); + + addList(/* list = */ memberList, /* kid = */ member); return true; } + UnaryNodeType newInitialYieldExpression(uint32_t begin, Node gen) { TokenPos pos(begin, begin + 1); return new_(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen); diff --git a/js/src/frontend/FunctionEmitter.cpp b/js/src/frontend/FunctionEmitter.cpp index 98dffe6b04..16c0e1fb06 100644 --- a/js/src/frontend/FunctionEmitter.cpp +++ b/js/src/frontend/FunctionEmitter.cpp @@ -477,13 +477,8 @@ bool FunctionScriptEmitter::prepareForBody() } if (funbox_->function()->kind() == JSFunction::FunctionKind::ClassConstructor) { - if (funbox_->isDerivedClassConstructor()) { - if (!bce_->emitCopyInitializersToLocalInitializers()) { - // [stack] - return false; - } - } else { - if (!bce_->emitInitializeInstanceFields(false)) { + if (!funbox_->isDerivedClassConstructor()) { + if (!bce_->emitInitializeInstanceFields()) { // [stack] return false; } diff --git a/js/src/frontend/ObjectEmitter.cpp b/js/src/frontend/ObjectEmitter.cpp index f421030e99..37c03935ab 100644 --- a/js/src/frontend/ObjectEmitter.cpp +++ b/js/src/frontend/ObjectEmitter.cpp @@ -531,13 +531,12 @@ ClassEmitter::ClassEmitter(BytecodeEmitter* bce) isClass_ = true; } -bool ClassEmitter::emitScope(JS::Handle scopeBindings, bool hasName) +bool ClassEmitter::emitScope(JS::Handle scopeBindings) { MOZ_ASSERT(propertyState_ == PropertyState::Start); MOZ_ASSERT(classState_ == ClassState::Start); - if (hasName) - tdzCacheForInnerName_.emplace(bce_); + tdzCache_.emplace(bce_); innerScope_.emplace(bce_); if (!innerScope_->enterLexical(bce_, ScopeKind::Lexical, scopeBindings)) @@ -717,7 +716,7 @@ bool ClassEmitter::emitEnd(Kind kind) } if (name_ != bce_->cx->names().empty) { - MOZ_ASSERT(tdzCacheForInnerName_.isSome()); + MOZ_ASSERT(tdzCache_.isSome()); MOZ_ASSERT(innerScope_.isSome()); if (!bce_->emitLexicalInitialization(name_)) { @@ -743,20 +742,21 @@ bool ClassEmitter::emitEnd(Kind kind) } } - tdzCacheForInnerName_.reset(); + tdzCache_.reset(); } else if (innerScope_.isSome()) { // [stack] CTOR MOZ_ASSERT(kind == Kind::Expression); - MOZ_ASSERT(tdzCacheForInnerName_.isNothing()); + MOZ_ASSERT(tdzCache_.isSome()); if (!innerScope_->leave(bce_)) return false; innerScope_.reset(); + tdzCache_.reset(); }else { // [stack] CTOR MOZ_ASSERT(kind == Kind::Expression); - MOZ_ASSERT(tdzCacheForInnerName_.isNothing()); + MOZ_ASSERT(tdzCache_.isNothing()); } // [stack] # class declaration diff --git a/js/src/frontend/ObjectEmitter.h b/js/src/frontend/ObjectEmitter.h index 952d4cf156..dd983a5b72 100644 --- a/js/src/frontend/ObjectEmitter.h +++ b/js/src/frontend/ObjectEmitter.h @@ -464,7 +464,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // `class {}` // ClassEmitter ce(this); -// ce.emitScope(scopeBindings, false); +// ce.emitScope(scopeBindings); // ce.emitClass(); // // ce.emitInitDefaultConstructor(Some(offset_of_class), @@ -474,7 +474,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // `class { constructor() { ... } }` // ClassEmitter ce(this); -// ce.emitScope(scopeBindings, false); +// ce.emitScope(scopeBindings); // ce.emitClass(); // // emit(function_for_constructor); @@ -484,7 +484,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // `class X { constructor() { ... } }` // ClassEmitter ce(this); -// ce.emitScope(scopeBindings, true); +// ce.emitScope(scopeBindings); // ce.emitClass(atom_of_X); // // ce.emitInitDefaultConstructor(Some(offset_of_class), @@ -494,7 +494,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // `class X { constructor() { ... } }` // ClassEmitter ce(this); -// ce.emitScope(scopeBindings, true); +// ce.emitScope(scopeBindings); // ce.emitClass(atom_of_X); // // emit(function_for_constructor); @@ -504,7 +504,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // `class X extends Y { constructor() { ... } }` // ClassEmitter ce(this); -// ce.emitScope(scopeBindings, true); +// ce.emitScope(scopeBindings); // // emit(Y); // ce.emitDerivedClass(atom_of_X); @@ -516,7 +516,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // `class X extends Y { constructor() { ... super.f(); ... } }` // ClassEmitter ce(this); -// ce.emitScope(scopeBindings, true); +// ce.emitScope(scopeBindings); // // emit(Y); // ce.emitDerivedClass(atom_of_X); @@ -630,7 +630,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter bool isDerived_ = false; - mozilla::Maybe tdzCacheForInnerName_; + mozilla::Maybe tdzCache_; mozilla::Maybe innerScope_; AutoSaveLocalStrictMode strictMode_; @@ -691,7 +691,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter public: explicit ClassEmitter(BytecodeEmitter* bce); - MOZ_MUST_USE bool emitScope(JS::Handle scopeBindings, bool hasName); + MOZ_MUST_USE bool emitScope(JS::Handle scopeBindings); // @param name // Name of the class (nullptr if this is anonymous class) diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 5919cfa735..9a91ee9b3e 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -2268,13 +2268,9 @@ class ClassNode : public TernaryNode MOZ_ASSERT(list->isKind(PNK_CLASSMEMBERLIST)); return list; } - bool isEmptyScope() const { - ParseNode* scope = kid3(); - return scope->as().isEmptyScope(); - } - Handle scopeBindings() const { - ParseNode* scope = kid3(); - return scope->as().scopeBindings(); + LexicalScopeNode* scopeBindings() const { + LexicalScopeNode* scope = &kid3()->as(); + return scope->isEmptyScope() ? nullptr : scope; } }; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index bc60503b25..e5daabc8d5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -2791,12 +2791,6 @@ Parser::functionBody(InHandling inHandling, YieldHandling yieldHan return null(); } - if (kind == FunctionSyntaxKind::DerivedClassConstructor) { - if (!noteDeclaredName(context->names().dotLocalInitializers, - DeclarationKind::Var, pos())) - return null(); - } - return finishLexicalScope(pc->varScope(), body); } @@ -3689,6 +3683,12 @@ Parser::functionFormalParametersAndBody(InHandling inHandling, FunctionBox* funbox = pc->functionBox(); RootedFunction fun(context, funbox->function()); + if (kind == FunctionSyntaxKind::ClassConstructor || + kind == FunctionSyntaxKind::DerivedClassConstructor) { + if (!noteUsedName(context->names().dotInitializers)) + return false; + } + // See below for an explanation why arrow function parameters and arrow // function bodies are parsed with different yield/await settings. { @@ -7501,7 +7501,11 @@ Parser::classMember(YieldHandling yieldHandling, DefaultHandling d return false; } - return handler.addClassFieldDefinition(classMembers, propName, initializer); + ClassFieldType field = handler.newClassFieldDefinition(propName, initializer); + if (!field) + return false; + + return handler.addClassMemberDefinition(classMembers, field); } if (propType != PropertyType::Getter && propType != PropertyType::Setter && @@ -7554,6 +7558,19 @@ Parser::classMember(YieldHandling yieldHandling, DefaultHandling d funName = propAtom; } + // .fieldKeys must be declared outside the scope .initializers is declared in, + // hence this extra scope. + Maybe dotInitializersScope; + if (isConstructor && !options().selfHostingMode) { + dotInitializersScope.emplace(this); + if (!dotInitializersScope->init(pc)) + return false; + + if (!noteDeclaredName(context->names().dotInitializers, DeclarationKind::Let, pos())) + return false; + } + + // Calling toString on constructors need to return the source text for // the entire class. The end offset is unknown at this point in // parsing and will be amended when class parsing finishes below. @@ -7565,7 +7582,18 @@ Parser::classMember(YieldHandling yieldHandling, DefaultHandling d handler.checkAndSetIsDirectRHSAnonFunction(funNode); JSOp op = JSOpFromPropertyType(propType); - return handler.addClassMethodDefinition(classMembers, propName, funNode, op, isStatic); + Node method = handler.newClassMethodDefinition(propName, funNode, op, isStatic); + if (!method) + return false; + + if (dotInitializersScope.isSome()) { + method = finishLexicalScope(*dotInitializersScope, method); + if (!method) + return false; + dotInitializersScope.reset(); + } + + return handler.addClassMemberDefinition(classMembers, method); } template @@ -7580,6 +7608,16 @@ Parser::finishClassConstructor(const ParseContext::ClassStatement& // JSOP_DERIVEDCONSTRUCTOR due to needing to emit calls to the field // initializers in the constructor. So, synthesize a new one. if (classStmt.constructorBox == nullptr && numFields > 0) { + MOZ_ASSERT(!options().selfHostingMode); + // Unconditionally create the scope here, because it's always the + // constructor. + ParseContext::Scope dotInitializersScope(this); + if (!dotInitializersScope.init(pc)) + return false; + + if (!noteDeclaredName(context->names().dotInitializers, DeclarationKind::Let, pos())) + return false; + // synthesizeConstructor assigns to classStmt.constructorBox FunctionNodeType synthesizedCtor = synthesizeConstructor(className, classStartOffset, hasHeritage); if (!synthesizedCtor) { @@ -7595,9 +7633,14 @@ Parser::finishClassConstructor(const ParseContext::ClassStatement& return false; } - if (!handler.addClassMethodDefinition(classMembers, constructorNameNode, - synthesizedCtor, JSOP_INITPROP, - /* isStatic = */ false)) { + ClassMethodType method = handler.newClassMethodDefinition(constructorNameNode, synthesizedCtor, + JSOP_INITPROP, /* isStatic = */ false); + if (!method) + return false; + + LexicalScopeNodeType scope = finishLexicalScope(dotInitializersScope, method); + + if (!handler.addClassMemberDefinition(classMembers, scope)) { return false; } } @@ -7712,35 +7755,6 @@ Parser::classDefinition(YieldHandling yieldHandling, break; } - if (numFields > 0) { - // .initializers is always closed over by the constructor when there are - // fields with initializers. However, there's some strange circumstances - // which prevents us from using the normal noteUsedName() system. We - // cannot call noteUsedName(".initializers") when parsing the constructor, - // because .initializers should be marked as used *only if* there are - // fields with initializers. Even if we haven't seen any fields yet, - // there may be fields after the constructor. - // Consider the following class: - // - // class C { - // constructor() { - // // do we noteUsedName(".initializers") here? - // } - // // ... because there might be some fields down here. - // } - // - // So, instead, at the end of class parsing (where we are now), we do some - // tricks to pretend that noteUsedName(".initializers") was called in the - // constructor. - if (!usedNames.markAsAlwaysClosedOver(context, context->names().dotInitializers, - pc->scriptId(), - pc->innermostScope()->id())) - return null(); - if (!noteDeclaredName(context->names().dotInitializers, - DeclarationKind::Let, namePos)) - return null(); - } - if (numFieldKeys > 0) { if (!noteDeclaredName(context->names().dotFieldKeys, DeclarationKind::Let, namePos)) return null(); @@ -7836,11 +7850,6 @@ Parser::synthesizeConstructor(HandleAtom className, uint32_t class pc->functionScope().useAsVarScope(pc); - // Push a LexicalScope on to the stack. - ParseContext::Scope lexicalScope(this); - if (!lexicalScope.init(pc)) - return null(); - auto stmtList = handler.newStatementList(synthesizedBodyPos); if (!stmtList) return null(); @@ -7848,14 +7857,8 @@ Parser::synthesizeConstructor(HandleAtom className, uint32_t class if (!noteUsedName(context->names().dotThis)) return null(); - // One might expect a noteUsedName(".initializers") here. See comment in - // GeneralParser::classDefinition on why it's not here. - - if (hasHeritage) { - if (!noteDeclaredName(context->names().dotLocalInitializers, - DeclarationKind::Var, synthesizedBodyPos)) - return null(); - } + if (!noteUsedName(context->names().dotInitializers)) + return null(); bool canSkipLazyClosedOverBindings = handler.canSkipLazyClosedOverBindings(); if (!declareFunctionThis(canSkipLazyClosedOverBindings)) @@ -7890,9 +7893,6 @@ Parser::synthesizeConstructor(HandleAtom className, uint32_t class if (!setThis) return null(); - if (!noteUsedName(context->names().dotLocalInitializers)) - return null(); - UnaryNodeType exprStatement = handler.newExprStatement(setThis, synthesizedBodyPos.end); if (!exprStatement) return null(); @@ -7900,7 +7900,7 @@ Parser::synthesizeConstructor(HandleAtom className, uint32_t class handler.addStatementToList(stmtList, exprStatement); } - auto initializerBody = finishLexicalScope(lexicalScope, stmtList); + auto initializerBody = finishLexicalScope(pc->varScope(), stmtList); if (!initializerBody) return null(); handler.setBeginPosition(initializerBody, stmtList); @@ -7969,15 +7969,7 @@ Parser::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH if (!funpc.init()) return null(); - // Push a VarScope on to the stack. - ParseContext::VarScope varScope(this); - if (!varScope.init(pc)) - return null(); - - // Push a LexicalScope on to the stack. - ParseContext::Scope lexicalScope(this); - if (!lexicalScope.init(pc)) - return null(); + pc->functionScope().useAsVarScope(pc); Node initializerExpr; TokenPos wholeInitializerPos; @@ -8081,7 +8073,7 @@ Parser::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH handler.addStatementToList(statementList, exprStatement); // Set the function's body to the field assignment. - LexicalScopeNodeType initializerBody = finishLexicalScope(lexicalScope, statementList); + LexicalScopeNodeType initializerBody = finishLexicalScope(pc->varScope(), statementList); if (!initializerBody) { return null(); } @@ -9975,7 +9967,7 @@ Parser::memberExpr(YieldHandling yieldHandling, TripledotHandling if (!nextMember) return null(); - if (!noteUsedName(context->names().dotLocalInitializers)) + if (!noteUsedName(context->names().dotInitializers)) return null(); } else { nextMember = memberCall(tt, lhs, yieldHandling, possibleError); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 607cff48f3..c1b6e989ab 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -331,8 +331,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS) MOZ_MUST_USE bool addShorthand(ListNodeType literal, NameNodeType name, NameNodeType expr) { return true; } MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin, Node inner) { return true; } MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node name, FunctionNodeType funNode, JSOp op) { return true; } - MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType memberList, Node key, FunctionNodeType funNode, JSOp op, bool isStatic) { return true; } - MOZ_MUST_USE bool addClassFieldDefinition(ListNodeType memberList, Node name, FunctionNodeType initializer) { return true; } + MOZ_MUST_USE Node newClassMethodDefinition(Node key, FunctionNodeType funNode, JSOp op, bool isStatic) { return NodeGeneric; } + MOZ_MUST_USE Node newClassFieldDefinition(Node name, FunctionNodeType initializer) { return NodeGeneric; } + MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member) { return true; } UnaryNodeType newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; } UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; } UnaryNodeType newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; } diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index bc2e4204e3..f69dfe3ca9 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -103,7 +103,6 @@ macro(dotGenerator, dotGenerator, ".generator") \ macro(dotThis, dotThis, ".this") \ macro(dotInitializers, dotInitializers, ".initializers") \ - macro(dotLocalInitializers, dotLocalInitializers, ".localInitializers") \ macro(dotFieldKeys, dotFieldKeys, ".fieldKeys") \ macro(each, each, "each") \ macro(elementType, elementType, "elementType") \