summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp7
-rw-r--r--js/src/frontend/ObjectEmitter.cpp24
-rw-r--r--js/src/frontend/ObjectEmitter.h46
-rw-r--r--js/src/frontend/ParseNode.h2
-rw-r--r--js/src/frontend/Parser.cpp9
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();