diff options
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 7 | ||||
-rw-r--r-- | js/src/frontend/ObjectEmitter.cpp | 24 | ||||
-rw-r--r-- | js/src/frontend/ObjectEmitter.h | 46 | ||||
-rw-r--r-- | js/src/frontend/ParseNode.h | 2 | ||||
-rw-r--r-- | js/src/frontend/Parser.cpp | 9 |
5 files changed, 72 insertions, 16 deletions
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 a13104870a..28cf4a1416 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 2504947314..1ee6071fdd 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<uint32_t>& 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<ParseHandler>::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<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldK handler.setFunctionBody(funNode, initializerBody); + if (pc->superScopeNeedsHomeObject()) { + funbox->setNeedsHomeObject(); + } + if (!finishFunction(false, true)) return null(); |