mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 20:07:30 +09:00
Issue #2142 - Optimize .initializers scoping and emitter
* Refactor code for emitting the .initializers array into ClassEmitter
* Only emit .initializers scope when actually required
* Remove unfinished code to handle non-present class field initialisers
* Use predicate count_if and any_of of ListNode
* Remove unnecessary parameters for class field parsing
Based-on: m-c 1553744, 1555979, 1555037/1, 1535804/{1-5}
This commit is contained in:
parent
c206114966
commit
e0b5528c29
10 changed files with 215 additions and 117 deletions
|
|
@ -2766,24 +2766,22 @@ ASTSerializer::classField(ClassField* classField, MutableHandleValue dst)
|
|||
{
|
||||
RootedValue key(cx), val(cx);
|
||||
// Dig through the lambda and get to the actual expression
|
||||
if (classField->initializer()) {
|
||||
ParseNode* value = classField->initializer()
|
||||
->body()
|
||||
->head()->as<LexicalScopeNode>()
|
||||
.scopeBody()->as<ListNode>()
|
||||
.head()->as<UnaryNode>()
|
||||
.kid()->as<BinaryNode>()
|
||||
.right();
|
||||
// RawUndefinedExpr is the node we use for "there is no initializer". If one
|
||||
// writes, literally, `x = undefined;`, it will not be a RawUndefinedExpr
|
||||
// node, but rather a variable reference.
|
||||
// Behavior for "there is no initializer" should be { ..., "init": null }
|
||||
if (value->getKind() != PNK_RAW_UNDEFINED) {
|
||||
if (!expression(value, &val))
|
||||
return false;
|
||||
} else {
|
||||
val.setNull();
|
||||
}
|
||||
ParseNode* value = classField->initializer()
|
||||
->body()
|
||||
->head()->as<LexicalScopeNode>()
|
||||
.scopeBody()->as<ListNode>()
|
||||
.head()->as<UnaryNode>()
|
||||
.kid()->as<BinaryNode>()
|
||||
.right();
|
||||
// RawUndefinedExpr is the node we use for "there is no initializer". If one
|
||||
// writes, literally, `x = undefined;`, it will not be a RawUndefinedExpr
|
||||
// node, but rather a variable reference.
|
||||
// Behavior for "there is no initializer" should be { ..., "init": null }
|
||||
if (value->getKind() != PNK_RAW_UNDEFINED) {
|
||||
if (!expression(value, &val))
|
||||
return false;
|
||||
} else {
|
||||
val.setNull();
|
||||
}
|
||||
return propertyName(&classField->name(), &key) &&
|
||||
builder.classField(key, val, &classField->pn_pos, dst);
|
||||
|
|
|
|||
|
|
@ -7942,18 +7942,7 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
FieldInitializers
|
||||
BytecodeEmitter::setupFieldInitializers(ListNode* classMembers)
|
||||
{
|
||||
size_t numFields = 0;
|
||||
|
||||
for (ParseNode* propdef : classMembers->contents()) {
|
||||
if (propdef->is<ClassField>()) {
|
||||
FunctionNode* initializer = propdef->as<ClassField>().initializer();
|
||||
// Don't include fields without initializers.
|
||||
if (initializer != nullptr) {
|
||||
numFields++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
size_t numFields = classMembers->count_if([](ParseNode* propdef) { return propdef->is<ClassField>(); });
|
||||
|
||||
return FieldInitializers(numFields);
|
||||
}
|
||||
|
|
@ -7984,15 +7973,10 @@ BytecodeEmitter::setupFieldInitializers(ListNode* classMembers)
|
|||
bool
|
||||
BytecodeEmitter::emitCreateFieldKeys(ListNode* obj)
|
||||
{
|
||||
size_t numFieldKeys = 0;
|
||||
for (ParseNode* propdef : obj->contents()) {
|
||||
if (propdef->is<ClassField>()) {
|
||||
ClassField* field = &propdef->as<ClassField>();
|
||||
if (field->name().getKind() == PNK_COMPUTED_NAME) {
|
||||
numFieldKeys++;
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t numFieldKeys = obj->count_if([](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>() &&
|
||||
propdef->as<ClassField>().name().getKind() == PNK_COMPUTED_NAME;
|
||||
});
|
||||
|
||||
if (numFieldKeys == 0)
|
||||
return true;
|
||||
|
|
@ -8021,8 +8005,9 @@ BytecodeEmitter::emitCreateFieldKeys(ListNode* obj)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitCreateFieldInitializers(ListNode* obj)
|
||||
BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj)
|
||||
{
|
||||
// [stack] HOMEOBJ HERITAGE?
|
||||
FieldInitializers fieldInitializers = setupFieldInitializers(obj);
|
||||
MOZ_ASSERT(fieldInitializers.valid);
|
||||
size_t numFields = fieldInitializers.numFieldInitializers;
|
||||
|
|
@ -8030,50 +8015,28 @@ BytecodeEmitter::emitCreateFieldInitializers(ListNode* obj)
|
|||
if (numFields == 0)
|
||||
return true;
|
||||
|
||||
// .initializers is a variable that stores an array of lambdas containing
|
||||
// code (the initializer) for each field. Upon an object's construction,
|
||||
// these lambdas will be called, defining the values.
|
||||
|
||||
NameOpEmitter noe(this, cx->names().dotInitializers,
|
||||
NameOpEmitter::Kind::Initialize);
|
||||
if (!noe.prepareForRhs()) {
|
||||
if (!ce.prepareForFieldInitializers(numFields)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitUint32Operand(JSOP_NEWARRAY, numFields)) {
|
||||
// [stack] CTOR? OBJ ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t curFieldIndex = 0;
|
||||
for (ParseNode* propdef : obj->contents()) {
|
||||
if (propdef->is<ClassField>()) {
|
||||
FunctionNode* initializer = propdef->as<ClassField>().initializer();
|
||||
if (initializer == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (!propdef->is<ClassField>())
|
||||
continue;
|
||||
|
||||
if (!emitTree(initializer)) {
|
||||
// [stack] CTOR? OBJ ARRAY LAMBDA
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitUint32Operand(JSOP_INITELEM_ARRAY, curFieldIndex)) {
|
||||
// [stack] CTOR? OBJ ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
curFieldIndex++;
|
||||
FunctionNode* initializer = propdef->as<ClassField>().initializer();
|
||||
if (!emitTree(initializer)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
|
||||
return false;
|
||||
}
|
||||
if (!ce.emitStoreFieldInitializer()) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!noe.emitAssignment()) {
|
||||
// [stack] CTOR? OBJ ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_POP)) {
|
||||
// [stack] CTOR? OBJ
|
||||
if (!ce.emitFieldInitializersEnd()) {
|
||||
// [stack] HOMEOBJ HERITAGE?
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -8698,20 +8661,37 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
}
|
||||
|
||||
if (constructor) {
|
||||
FunctionNode* ctor;
|
||||
// .fieldKeys must be declared outside the scope .initializers is declared
|
||||
// in, hence this extra scope.
|
||||
// See |Parser::classMember(...)| for the reason why |.initializers| is
|
||||
// created within its own scope.
|
||||
Maybe<LexicalScopeEmitter> lse;
|
||||
FunctionNode* ctor;
|
||||
if (constructor->is<LexicalScopeNode>()) {
|
||||
lse.emplace(this);
|
||||
if (!lse->emitScope(ScopeKind::Lexical, constructor->as<LexicalScopeNode>().scopeBindings()))
|
||||
return false;
|
||||
LexicalScopeNode* constructorScope = &constructor->as<LexicalScopeNode>();
|
||||
|
||||
// Any class with field initializers will have a constructor
|
||||
if (!emitCreateFieldInitializers(classMembers))
|
||||
return false;
|
||||
ctor = &constructor->as<LexicalScopeNode>().scopeBody()->as<ClassMethod>().method();
|
||||
// The constructor scope should only contain the |.initializers| binding.
|
||||
MOZ_ASSERT(!constructorScope->isEmptyScope());
|
||||
MOZ_ASSERT(constructorScope->scopeBindings()->length == 1);
|
||||
MOZ_ASSERT(constructorScope->scopeBindings()->trailingNames[0].name() ==
|
||||
cx->names().dotInitializers);
|
||||
|
||||
// As an optimization omit the |.initializers| binding when no instance
|
||||
// fields are present.
|
||||
bool hasInstanceFields = classMembers->any_of([](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>();
|
||||
});
|
||||
if (hasInstanceFields) {
|
||||
lse.emplace(this);
|
||||
if (!lse->emitScope(ScopeKind::Lexical, constructorScope->scopeBindings()))
|
||||
return false;
|
||||
|
||||
// Any class with field initializers will have a constructor
|
||||
if (!emitCreateFieldInitializers(ce, classMembers))
|
||||
return false;
|
||||
}
|
||||
ctor = &constructorScope->scopeBody()->as<ClassMethod>().method();
|
||||
} else {
|
||||
// The |.initializers| binding is never emitted when in self-hosting mode.
|
||||
MOZ_ASSERT(emitterMode == BytecodeEmitter::SelfHosting);
|
||||
ctor = &constructor->as<ClassMethod>().method();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ typedef Vector<jsbytecode, 256> BytecodeVector;
|
|||
typedef Vector<jssrcnote, 64> SrcNotesVector;
|
||||
|
||||
class CallOrNewEmitter;
|
||||
class ClassEmitter;
|
||||
class ElemOpEmitter;
|
||||
class EmitterScope;
|
||||
class NestableControl;
|
||||
|
|
@ -531,7 +532,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
|
||||
FieldInitializers setupFieldInitializers(ListNode* classMembers);
|
||||
MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj);
|
||||
MOZ_MUST_USE bool emitCreateFieldInitializers(ListNode* obj);
|
||||
MOZ_MUST_USE bool emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj);
|
||||
const FieldInitializers& findFieldInitializersForCall();
|
||||
MOZ_MUST_USE bool emitInitializeInstanceFields();
|
||||
|
||||
|
|
|
|||
|
|
@ -487,7 +487,6 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
UnaryNodeType newInitialYieldExpression(uint32_t begin, Node gen) {
|
||||
TokenPos pos(begin, begin + 1);
|
||||
return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
|
||||
|
|
|
|||
|
|
@ -484,6 +484,71 @@ bool ObjectEmitter::emitObject(size_t propertyCount)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::prepareForFieldInitializers(size_t numFields)
|
||||
{
|
||||
MOZ_ASSERT(classState_ == ClassState::Class);
|
||||
|
||||
// .initializers is a variable that stores an array of lambdas containing
|
||||
// code (the initializer) for each field. Upon an object's construction,
|
||||
// these lambdas will be called, defining the values.
|
||||
initializersAssignment_.emplace(bce_, bce_->cx->names().dotInitializers,
|
||||
NameOpEmitter::Kind::Initialize);
|
||||
if (!initializersAssignment_->prepareForRhs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce_->emitUint32Operand(JSOP_NEWARRAY, numFields)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(fieldIndex_ == 0);
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::FieldInitializers;
|
||||
numFields_ = numFields;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitStoreFieldInitializer()
|
||||
{
|
||||
MOZ_ASSERT(classState_ == ClassState::FieldInitializers);
|
||||
MOZ_ASSERT(fieldIndex_ < numFields_);
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY METHOD
|
||||
|
||||
if (!bce_->emitUint32Operand(JSOP_INITELEM_ARRAY, fieldIndex_)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
fieldIndex_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitFieldInitializersEnd()
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start ||
|
||||
propertyState_ == PropertyState::Init);
|
||||
MOZ_ASSERT(classState_ == ClassState::FieldInitializers);
|
||||
MOZ_ASSERT(fieldIndex_ == numFields_);
|
||||
|
||||
if (!initializersAssignment_->emitAssignment()) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
return false;
|
||||
}
|
||||
initializersAssignment_.reset();
|
||||
|
||||
if (!bce_->emit1(JSOP_POP)) {
|
||||
// [stack] HOMEOBJ HERITAGE?
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::FieldInitializersEnd;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjectEmitter::emitEnd()
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start ||
|
||||
|
|
@ -614,7 +679,8 @@ void ClassEmitter::setName(JS::Handle<JSAtom*> name)
|
|||
bool ClassEmitter::emitInitConstructor(bool needsHomeObject)
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class ||
|
||||
classState_ == ClassState::FieldInitializersEnd);
|
||||
|
||||
// [stack] HOMEOBJ CTOR
|
||||
|
||||
|
|
@ -640,7 +706,8 @@ bool ClassEmitter::emitInitDefaultConstructor(const Maybe<uint32_t>& classStart,
|
|||
const Maybe<uint32_t>& classEnd)
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class ||
|
||||
classState_ == ClassState::FieldInitializersEnd);
|
||||
|
||||
if (classStart && classEnd) {
|
||||
// In the case of default class constructors, emit the start and end
|
||||
|
|
@ -706,7 +773,8 @@ bool ClassEmitter::emitEnd(Kind kind)
|
|||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start ||
|
||||
propertyState_ == PropertyState::Init);
|
||||
MOZ_ASSERT(classState_ == ClassState::InitConstructor);
|
||||
MOZ_ASSERT(classState_ == ClassState::InitConstructor ||
|
||||
classState_ == ClassState::FieldInitializersEnd);
|
||||
|
||||
// [stack] CTOR HOMEOBJ
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "jsscript.h" // FunctionAsyncKind
|
||||
|
||||
#include "frontend/EmitterScope.h" // EmitterScope
|
||||
#include "frontend/NameOpEmitter.h" // NameOpEmitter
|
||||
#include "frontend/TDZCheckCache.h" // TDZCheckCache
|
||||
#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
|
||||
#include "vm/String.h" // JSAtom
|
||||
|
|
@ -527,6 +528,23 @@ class MOZ_RAII AutoSaveLocalStrictMode
|
|||
//
|
||||
// ce.emitEnd(ClassEmitter::Kind::Expression);
|
||||
//
|
||||
// `class X extends Y { field0 = expr0; ... }`
|
||||
// ClassEmitter ce(this);
|
||||
// ce.emitScope(scopeBindings);
|
||||
// emit(Y);
|
||||
// ce.emitDerivedClass(atom_of_X, nullptr, false);
|
||||
//
|
||||
// ce.prepareForFieldInitializers(fields.length());
|
||||
// for (auto field : fields) {
|
||||
// emit(field.expr_method());
|
||||
// ce.emitStoreFieldInitializer();
|
||||
// }
|
||||
// ce.emitFieldInitializersEnd();
|
||||
//
|
||||
// emit(function_for_constructor);
|
||||
// ce.emitInitConstructor(/* needsHomeObject = */ false);
|
||||
// ce.emitEnd(ClassEmitter::Kind::Expression);
|
||||
//
|
||||
// `m() {}` in class
|
||||
// // after emitInitConstructor/emitInitDefaultConstructor
|
||||
// ce.prepareForPropValue(Some(offset_of_m));
|
||||
|
|
@ -655,6 +673,21 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
// |
|
||||
// +-------------------------------+
|
||||
// |
|
||||
// | prepareForFieldInitializers +-------------------+
|
||||
// +----------------------------->| FieldInitializers |-+
|
||||
// | +-------------------+ |
|
||||
// | |
|
||||
// | +-------------------------------------------------+
|
||||
// | |
|
||||
// | | (expr emitStoreFieldInitializer)*
|
||||
// | |
|
||||
// | |
|
||||
// | | emitFieldInitializersEnd +----------------------+
|
||||
// | +-------------------------->| FieldInitializersEnd |-+
|
||||
// | +----------------------+ |
|
||||
// | |
|
||||
// |<------------------------------------------------------+
|
||||
// |
|
||||
// |
|
||||
// | emitInitConstructor +-----------------+
|
||||
// +-+--------------------------->+->| InitConstructor |-+
|
||||
|
|
@ -680,13 +713,23 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
// After calling emitInitConstructor or emitInitDefaultConstructor.
|
||||
InitConstructor,
|
||||
|
||||
// After calling prepareForFieldInitializers
|
||||
// and 0 or more calls to emitFieldInitializersEnd.
|
||||
FieldInitializers,
|
||||
|
||||
// After calling emitFieldInitializersEnd.
|
||||
FieldInitializersEnd,
|
||||
|
||||
// After calling emitEnd.
|
||||
End,
|
||||
};
|
||||
ClassState classState_ = ClassState::Start;
|
||||
size_t numFields_ = 0;
|
||||
#endif
|
||||
|
||||
JS::Rooted<JSAtom*> name_;
|
||||
mozilla::Maybe<NameOpEmitter> initializersAssignment_;
|
||||
size_t fieldIndex_ = 0;
|
||||
|
||||
public:
|
||||
explicit ClassEmitter(BytecodeEmitter* bce);
|
||||
|
|
@ -715,6 +758,10 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
const mozilla::Maybe<uint32_t>& classStart,
|
||||
const mozilla::Maybe<uint32_t>& classEnd);
|
||||
|
||||
MOZ_MUST_USE bool prepareForFieldInitializers(size_t numFields);
|
||||
MOZ_MUST_USE bool emitStoreFieldInitializer();
|
||||
MOZ_MUST_USE bool emitFieldInitializersEnd();
|
||||
|
||||
MOZ_MUST_USE bool emitEnd(Kind kind);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -2143,7 +2143,7 @@ class ClassField : public BinaryNode
|
|||
public:
|
||||
ClassField(ParseNode* name, ParseNode* initializer)
|
||||
: BinaryNode(PNK_CLASSFIELD, JSOP_NOP,
|
||||
initializer == nullptr ? name->pn_pos : TokenPos::box(name->pn_pos, initializer->pn_pos),
|
||||
TokenPos::box(name->pn_pos, initializer->pn_pos),
|
||||
name, initializer)
|
||||
{
|
||||
}
|
||||
|
|
@ -2156,9 +2156,7 @@ class ClassField : public BinaryNode
|
|||
|
||||
ParseNode& name() const { return *left(); }
|
||||
|
||||
FunctionNode* initializer() const {
|
||||
return right() ? &right()->as<FunctionNode>() : nullptr;
|
||||
}
|
||||
FunctionNode* initializer() const { return &right()->as<FunctionNode>(); }
|
||||
};
|
||||
|
||||
class SwitchStatement : public BinaryNode
|
||||
|
|
|
|||
|
|
@ -557,13 +557,10 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
|
|||
}
|
||||
|
||||
void
|
||||
FunctionBox::initFieldInitializer(ParseContext* enclosing, bool hasHeritage)
|
||||
FunctionBox::initFieldInitializer(ParseContext* enclosing)
|
||||
{
|
||||
this->initWithEnclosingParseContext(enclosing, FunctionSyntaxKind::Expression);
|
||||
allowSuperProperty_ = false;
|
||||
allowSuperCall_ = false;
|
||||
this->initWithEnclosingParseContext(enclosing, FunctionSyntaxKind::Method);
|
||||
allowArguments_ = false;
|
||||
needsThisTDZChecks_ = hasHeritage;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -7419,7 +7416,7 @@ JSOpFromPropertyType(PropertyType propType)
|
|||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling defaultHandling,
|
||||
Parser<ParseHandler>::classMember(YieldHandling yieldHandling,
|
||||
const ParseContext::ClassStatement& classStmt,
|
||||
HandlePropertyName className,
|
||||
uint32_t classStartOffset, bool hasHeritage,
|
||||
|
|
@ -7492,8 +7489,7 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
|
|||
|
||||
numFields++;
|
||||
|
||||
FunctionNodeType initializer = fieldInitializerOpt(yieldHandling, hasHeritage,
|
||||
propAtom, numFieldKeys);
|
||||
FunctionNodeType initializer = fieldInitializerOpt(propAtom, numFieldKeys);
|
||||
if (!initializer)
|
||||
return false;
|
||||
|
||||
|
|
@ -7558,8 +7554,25 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling, DefaultHandling d
|
|||
funName = propAtom;
|
||||
}
|
||||
|
||||
// .fieldKeys must be declared outside the scope .initializers is declared in,
|
||||
// hence this extra scope.
|
||||
// When |super()| is invoked, we search for the nearest scope containing
|
||||
// |.initializers| to initialize the class fields. This set-up precludes
|
||||
// declaring |.initializers| in the class scope, because in some syntactic
|
||||
// contexts |super()| can appear nested in a class, while actually belonging
|
||||
// to an outer class definition.
|
||||
//
|
||||
// Example:
|
||||
// class Outer extends Base {
|
||||
// field = 1;
|
||||
// constructor() {
|
||||
// class Inner {
|
||||
// field = 2;
|
||||
//
|
||||
// // The super() call in the computed property name mustn't access
|
||||
// // Inner's |.initializers| array, but instead Outer's.
|
||||
// [super()]() {}
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
Maybe<ParseContext::Scope> dotInitializersScope;
|
||||
if (isConstructor && !options().selfHostingMode) {
|
||||
dotInitializersScope.emplace(this);
|
||||
|
|
@ -7747,9 +7760,8 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
size_t numFieldKeys = 0;
|
||||
for (;;) {
|
||||
bool done;
|
||||
if (!classMember(yieldHandling, defaultHandling, classStmt, className,
|
||||
classStartOffset, hasHeritage, numFields, numFieldKeys,
|
||||
classMembers, &done))
|
||||
if (!classMember(yieldHandling, classStmt, className, classStartOffset,
|
||||
hasHeritage, numFields, numFieldKeys, classMembers, &done))
|
||||
return null();
|
||||
if (done)
|
||||
break;
|
||||
|
|
@ -7831,7 +7843,6 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
if (!funbox)
|
||||
return null();
|
||||
funbox->initWithEnclosingParseContext(pc, functionSyntaxKind);
|
||||
handler.setFunctionBox(funNode, funbox);
|
||||
funbox->setEnd(pos().end);
|
||||
|
||||
// Push a ParseContext on to the stack.
|
||||
|
|
@ -7944,8 +7955,7 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
|
||||
template <class ParseHandler>
|
||||
typename ParseHandler::FunctionNodeType
|
||||
Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasHeritage,
|
||||
HandleAtom propAtom, size_t& numFieldKeys)
|
||||
Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldKeys)
|
||||
{
|
||||
bool hasInitializer = false;
|
||||
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
|
||||
|
|
@ -7983,8 +7993,7 @@ Parser<ParseHandler>::fieldInitializerOpt(YieldHandling yieldHandling, bool hasH
|
|||
FunctionAsyncKind::SyncFunction, false);
|
||||
if (!funbox)
|
||||
return null();
|
||||
funbox->initFieldInitializer(pc, hasHeritage);
|
||||
handler.setFunctionBox(funNode, funbox);
|
||||
funbox->initFieldInitializer(pc);
|
||||
funbox->setStart(tokenStream, firstTokenPos);
|
||||
|
||||
// Push a SourceParseContext on to the stack.
|
||||
|
|
|
|||
|
|
@ -1489,7 +1489,6 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
|||
ClassNodeType classDefinition(YieldHandling yieldHandling, ClassContext classContext,
|
||||
DefaultHandling defaultHandling);
|
||||
MOZ_MUST_USE bool classMember(YieldHandling yieldHandling,
|
||||
DefaultHandling defaultHandling,
|
||||
const ParseContext::ClassStatement& classStmt,
|
||||
HandlePropertyName className,
|
||||
uint32_t classStartOffset, bool hasHeritage,
|
||||
|
|
@ -1502,8 +1501,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
|||
uint32_t classStartOffset, uint32_t classEndOffset,
|
||||
size_t numFieldsWithInitializers, ListNodeType& classMembers);
|
||||
|
||||
FunctionNodeType fieldInitializerOpt(YieldHandling yieldHandling, bool hasHeritage,
|
||||
HandleAtom atom, size_t& numFieldKeys);
|
||||
FunctionNodeType fieldInitializerOpt(HandleAtom atom, size_t& numFieldKeys);
|
||||
FunctionNodeType synthesizeConstructor(HandleAtom className,
|
||||
uint32_t classNameOffset,
|
||||
bool hasHeritage);
|
||||
|
|
|
|||
|
|
@ -455,7 +455,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
void initFromLazyFunction();
|
||||
void initStandaloneFunction(Scope* enclosingScope);
|
||||
void initWithEnclosingParseContext(ParseContext* enclosing, FunctionSyntaxKind kind);
|
||||
void initFieldInitializer(ParseContext* enclosing, bool hasHeritage);
|
||||
void initFieldInitializer(ParseContext* enclosing);
|
||||
|
||||
ObjectBox* toObjectBox() override { return this; }
|
||||
JSFunction* function() const { return &object->as<JSFunction>(); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue