diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 931b414f10..47ea774f86 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -8029,6 +8029,13 @@ BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj) // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA return false; } + if (initializer->funbox()->needsHomeObject()) { + MOZ_ASSERT(initializer->funbox()->function()->allowSuperProperty()); + if (!ce.emitFieldInitializerHomeObject()) { + // [stack] CTOR OBJ ARRAY LAMBDA + return false; + } + } if (!ce.emitStoreFieldInitializer()) { // [stack] HOMEOBJ HERITAGE? ARRAY return false; diff --git a/js/src/frontend/ObjectEmitter.cpp b/js/src/frontend/ObjectEmitter.cpp index fc4ff4d303..0cb56c8f3e 100644 --- a/js/src/frontend/ObjectEmitter.cpp +++ b/js/src/frontend/ObjectEmitter.cpp @@ -510,9 +510,25 @@ bool ClassEmitter::prepareForFieldInitializers(size_t numFields) return true; } -bool ClassEmitter::emitStoreFieldInitializer() +bool ClassEmitter::emitFieldInitializerHomeObject() { MOZ_ASSERT(classState_ == ClassState::FieldInitializers); + // [stack] OBJ HERITAGE? ARRAY METHOD + if (!bce_->emit2(JSOP_INITHOMEOBJECT, isDerived_ ? 2 : 1)) { + // [stack] OBJ HERITAGE? ARRAY METHOD + return false; + } + +#ifdef DEBUG + classState_ = ClassState::FieldInitializerWithHomeObject; +#endif + return true; +} + +bool ClassEmitter::emitStoreFieldInitializer() +{ + MOZ_ASSERT(classState_ == ClassState::FieldInitializers || + classState_ == ClassState::FieldInitializerWithHomeObject); MOZ_ASSERT(fieldIndex_ < numFields_); // [stack] HOMEOBJ HERITAGE? ARRAY METHOD @@ -522,6 +538,9 @@ bool ClassEmitter::emitStoreFieldInitializer() } fieldIndex_++; +#ifdef DEBUG + classState_ = ClassState::FieldInitializers; +#endif return true; } @@ -529,7 +548,8 @@ bool ClassEmitter::emitFieldInitializersEnd() { MOZ_ASSERT(propertyState_ == PropertyState::Start || propertyState_ == PropertyState::Init); - MOZ_ASSERT(classState_ == ClassState::FieldInitializers); + MOZ_ASSERT(classState_ == ClassState::FieldInitializers || + classState_ == ClassState::FieldInitializerWithHomeObject); MOZ_ASSERT(fieldIndex_ == numFields_); if (!initializersAssignment_->emitAssignment()) { diff --git a/js/src/frontend/ObjectEmitter.h b/js/src/frontend/ObjectEmitter.h index 423284a455..38408f7650 100644 --- a/js/src/frontend/ObjectEmitter.h +++ b/js/src/frontend/ObjectEmitter.h @@ -536,7 +536,7 @@ class MOZ_RAII AutoSaveLocalStrictMode // // ce.prepareForFieldInitializers(fields.length()); // for (auto field : fields) { -// emit(field.expr_method()); +// emit(field.initializer_method()); // ce.emitStoreFieldInitializer(); // } // ce.emitFieldInitializersEnd(); @@ -545,6 +545,18 @@ class MOZ_RAII AutoSaveLocalStrictMode // ce.emitInitConstructor(/* needsHomeObject = */ false); // ce.emitEnd(ClassEmitter::Kind::Expression); // +// `class X { field0 = super.method(); ... }` +// // after emitClass/emitDerivedClass +// ce.prepareForFieldInitializers(1); +// for (auto field : fields) { +// emit(field.initializer_method()); +// if (field.initializer_contains_super_or_eval()) { +// ce.emitFieldInitializerHomeObject(); +// } +// ce.emitStoreFieldInitializer(); +// } +// ce.emitFieldInitializersEnd(); +// // `m() {}` in class // // after emitInitConstructor/emitInitDefaultConstructor // ce.prepareForPropValue(Some(offset_of_m)); @@ -673,14 +685,24 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter // | // +-------------------------------+ // | - // | prepareForFieldInitializers +-------------------+ - // +----------------------------->| FieldInitializers |-+ - // | +-------------------+ | - // | | - // | +-------------------------------------------------+ - // | | - // | | (expr emitStoreFieldInitializer)* - // | | + // | prepareForFieldInitializers + // +-----------------------------+ + // | | + // | | +-------------------+ + // | +--------------------->+--->| FieldInitializers |-+ + // | | +-------------------+ | + // | | | + // | | (emit initializer method) | + // | | +<--------------------------------------------+ + // | | | + // | | | emitFieldInitializerHomeObject +--------------------------------+ + // | | +-------------------------------->| FieldInitializerWithHomeObject |-+ + // | | | +--------------------------------+ | + // | | | | + // | | +------------------------------------------------------------------->+ + // | | | + // | | emitStoreFieldInitializer | + // | +<--+<-----------------------------------------------------------------------+ // | | // | | emitFieldInitializersEnd +----------------------+ // | +-------------------------->| FieldInitializersEnd |-+ @@ -714,9 +736,12 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter InitConstructor, // After calling prepareForFieldInitializers - // and 0 or more calls to emitFieldInitializersEnd. + // and 0 or more calls to emitStoreFieldInitializer. FieldInitializers, + // After calling emitFieldInitializerHomeObject + FieldInitializerWithHomeObject, + // After calling emitFieldInitializersEnd. FieldInitializersEnd, @@ -759,6 +784,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter const mozilla::Maybe& classEnd); MOZ_MUST_USE bool prepareForFieldInitializers(size_t numFields); + MOZ_MUST_USE bool emitFieldInitializerHomeObject(); MOZ_MUST_USE bool emitStoreFieldInitializer(); MOZ_MUST_USE bool emitFieldInitializersEnd(); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index c4e6945e5a..554703da46 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -625,7 +625,7 @@ enum class FunctionSyntaxKind Expression, // A non-arrow function expression. Statement, // A named function appearing as a Statement. Arrow, - Method, + Method, // Method of a class or object. Field initializers also desugar to methods. ClassConstructor, DerivedClassConstructor, Getter, diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index e74a8d3ee9..b5044c6ca2 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -222,7 +222,6 @@ SharedContext::computeAllowSyntax(Scope* scope) allowSuperProperty_ = fun->allowSuperProperty(); allowSuperCall_ = fun->isDerivedClassConstructor(); if (funScope->isFieldInitializer()) { - allowSuperProperty_ = false; allowSuperCall_ = false; allowArguments_ = false; } @@ -7975,14 +7974,14 @@ Parser::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldK // Create the anonymous function object. RootedFunction fun(context, - newFunction(nullptr, FunctionSyntaxKind::Expression, + newFunction(nullptr, FunctionSyntaxKind::Method, GeneratorKind::NotGenerator, FunctionAsyncKind::SyncFunction)); if (!fun) return null(); // Create the top-level field initializer node. - FunctionNodeType funNode = handler.newFunction(FunctionSyntaxKind::Expression, firstTokenPos); + FunctionNodeType funNode = handler.newFunction(FunctionSyntaxKind::Method, firstTokenPos); if (!funNode) return null(); @@ -8117,6 +8116,10 @@ Parser::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldK handler.setFunctionBody(funNode, initializerBody); + if (pc->superScopeNeedsHomeObject()) { + funbox->setNeedsHomeObject(); + } + if (!finishFunction(false, true)) return null();