Issue #2142 - Support SuperProperty in field initializers

Based-on: m-c 1555037/2
This commit is contained in:
Martok 2023-04-10 18:19:26 +02:00 • committed by roytam1
commit b187006a7e
5 changed files with 72 additions and 16 deletions

View file

@ -8029,6 +8029,13 @@ BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj)
// [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA // [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
return false; 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()) { if (!ce.emitStoreFieldInitializer()) {
// [stack] HOMEOBJ HERITAGE? ARRAY // [stack] HOMEOBJ HERITAGE? ARRAY
return false; return false;

View file

@ -510,9 +510,25 @@ bool ClassEmitter::prepareForFieldInitializers(size_t numFields)
return true; return true;
} }
bool ClassEmitter::emitStoreFieldInitializer() bool ClassEmitter::emitFieldInitializerHomeObject()
{ {
MOZ_ASSERT(classState_ == ClassState::FieldInitializers); 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_); MOZ_ASSERT(fieldIndex_ < numFields_);
// [stack] HOMEOBJ HERITAGE? ARRAY METHOD // [stack] HOMEOBJ HERITAGE? ARRAY METHOD
@ -522,6 +538,9 @@ bool ClassEmitter::emitStoreFieldInitializer()
} }
fieldIndex_++; fieldIndex_++;
#ifdef DEBUG
classState_ = ClassState::FieldInitializers;
#endif
return true; return true;
} }
@ -529,7 +548,8 @@ bool ClassEmitter::emitFieldInitializersEnd()
{ {
MOZ_ASSERT(propertyState_ == PropertyState::Start || MOZ_ASSERT(propertyState_ == PropertyState::Start ||
propertyState_ == PropertyState::Init); propertyState_ == PropertyState::Init);
MOZ_ASSERT(classState_ == ClassState::FieldInitializers); MOZ_ASSERT(classState_ == ClassState::FieldInitializers ||
classState_ == ClassState::FieldInitializerWithHomeObject);
MOZ_ASSERT(fieldIndex_ == numFields_); MOZ_ASSERT(fieldIndex_ == numFields_);
if (!initializersAssignment_->emitAssignment()) { if (!initializersAssignment_->emitAssignment()) {

View file

@ -536,7 +536,7 @@ class MOZ_RAII AutoSaveLocalStrictMode
// //
// ce.prepareForFieldInitializers(fields.length()); // ce.prepareForFieldInitializers(fields.length());
// for (auto field : fields) { // for (auto field : fields) {
// emit(field.expr_method()); // emit(field.initializer_method());
// ce.emitStoreFieldInitializer(); // ce.emitStoreFieldInitializer();
// } // }
// ce.emitFieldInitializersEnd(); // ce.emitFieldInitializersEnd();
@ -545,6 +545,18 @@ class MOZ_RAII AutoSaveLocalStrictMode
// ce.emitInitConstructor(/* needsHomeObject = */ false); // ce.emitInitConstructor(/* needsHomeObject = */ false);
// ce.emitEnd(ClassEmitter::Kind::Expression); // 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 // `m() {}` in class
// // after emitInitConstructor/emitInitDefaultConstructor // // after emitInitConstructor/emitInitDefaultConstructor
// ce.prepareForPropValue(Some(offset_of_m)); // ce.prepareForPropValue(Some(offset_of_m));
@ -673,14 +685,24 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
// | // |
// +-------------------------------+ // +-------------------------------+
// | // |
// | prepareForFieldInitializers +-------------------+ // | prepareForFieldInitializers
// +----------------------------->| FieldInitializers |-+ // +-----------------------------+
// | +-------------------+ | // | |
// | | // | | +-------------------+
// | +-------------------------------------------------+ // | +--------------------->+--->| FieldInitializers |-+
// | | // | | +-------------------+ |
// | | (expr emitStoreFieldInitializer)* // | | |
// | | // | | (emit initializer method) |
// | | +<--------------------------------------------+
// | | |
// | | | emitFieldInitializerHomeObject +--------------------------------+
// | | +-------------------------------->| FieldInitializerWithHomeObject |-+
// | | | +--------------------------------+ |
// | | | |
// | | +------------------------------------------------------------------->+
// | | |
// | | emitStoreFieldInitializer |
// | +<--+<-----------------------------------------------------------------------+
// | | // | |
// | | emitFieldInitializersEnd +----------------------+ // | | emitFieldInitializersEnd +----------------------+
// | +-------------------------->| FieldInitializersEnd |-+ // | +-------------------------->| FieldInitializersEnd |-+
@ -714,9 +736,12 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
InitConstructor, InitConstructor,
// After calling prepareForFieldInitializers // After calling prepareForFieldInitializers
// and 0 or more calls to emitFieldInitializersEnd. // and 0 or more calls to emitStoreFieldInitializer.
FieldInitializers, FieldInitializers,
// After calling emitFieldInitializerHomeObject
FieldInitializerWithHomeObject,
// After calling emitFieldInitializersEnd. // After calling emitFieldInitializersEnd.
FieldInitializersEnd, FieldInitializersEnd,
@ -759,6 +784,7 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
const mozilla::Maybe<uint32_t>& classEnd); const mozilla::Maybe<uint32_t>& classEnd);
MOZ_MUST_USE bool prepareForFieldInitializers(size_t numFields); MOZ_MUST_USE bool prepareForFieldInitializers(size_t numFields);
MOZ_MUST_USE bool emitFieldInitializerHomeObject();
MOZ_MUST_USE bool emitStoreFieldInitializer(); MOZ_MUST_USE bool emitStoreFieldInitializer();
MOZ_MUST_USE bool emitFieldInitializersEnd(); MOZ_MUST_USE bool emitFieldInitializersEnd();

View file

@ -625,7 +625,7 @@ enum class FunctionSyntaxKind
Expression, // A non-arrow function expression. Expression, // A non-arrow function expression.
Statement, // A named function appearing as a Statement. Statement, // A named function appearing as a Statement.
Arrow, Arrow,
Method, Method, // Method of a class or object. Field initializers also desugar to methods.
ClassConstructor, ClassConstructor,
DerivedClassConstructor, DerivedClassConstructor,
Getter, Getter,

View file

@ -222,7 +222,6 @@ SharedContext::computeAllowSyntax(Scope* scope)
allowSuperProperty_ = fun->allowSuperProperty(); allowSuperProperty_ = fun->allowSuperProperty();
allowSuperCall_ = fun->isDerivedClassConstructor(); allowSuperCall_ = fun->isDerivedClassConstructor();
if (funScope->isFieldInitializer()) { if (funScope->isFieldInitializer()) {
allowSuperProperty_ = false;
allowSuperCall_ = false; allowSuperCall_ = false;
allowArguments_ = false; allowArguments_ = false;
} }
@ -7975,14 +7974,14 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldK
// Create the anonymous function object. // Create the anonymous function object.
RootedFunction fun(context, RootedFunction fun(context,
newFunction(nullptr, FunctionSyntaxKind::Expression, newFunction(nullptr, FunctionSyntaxKind::Method,
GeneratorKind::NotGenerator, GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction)); FunctionAsyncKind::SyncFunction));
if (!fun) if (!fun)
return null(); return null();
// Create the top-level field initializer node. // Create the top-level field initializer node.
FunctionNodeType funNode = handler.newFunction(FunctionSyntaxKind::Expression, firstTokenPos); FunctionNodeType funNode = handler.newFunction(FunctionSyntaxKind::Method, firstTokenPos);
if (!funNode) if (!funNode)
return null(); return null();
@ -8117,6 +8116,10 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldK
handler.setFunctionBody(funNode, initializerBody); handler.setFunctionBody(funNode, initializerBody);
if (pc->superScopeNeedsHomeObject()) {
funbox->setNeedsHomeObject();
}
if (!finishFunction(false, true)) if (!finishFunction(false, true))
return null(); return null();