mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 01:08:39 +09:00
Issue #2142 - Parse and process static class fields
Based-on: m-c 1535804/{6,7}
This commit is contained in:
parent
b187006a7e
commit
c3b19191f3
10 changed files with 426 additions and 145 deletions
|
|
@ -5704,7 +5704,8 @@ BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto /* = false
|
|||
}
|
||||
|
||||
if (classContentsIfConstructor) {
|
||||
fun->lazyScript()->setFieldInitializers(setupFieldInitializers(classContentsIfConstructor));
|
||||
fun->lazyScript()->setFieldInitializers(setupFieldInitializers(classContentsIfConstructor,
|
||||
FieldPlacement::Instance));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -5732,7 +5733,7 @@ BytecodeEmitter::emitFunction(FunctionNode* funNode, bool needsProto /* = false
|
|||
|
||||
FieldInitializers fieldInitializers = FieldInitializers::Invalid();
|
||||
if (classContentsIfConstructor) {
|
||||
fieldInitializers = setupFieldInitializers(classContentsIfConstructor);
|
||||
fieldInitializers = setupFieldInitializers(classContentsIfConstructor, FieldPlacement::Instance);
|
||||
}
|
||||
|
||||
BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
|
||||
|
|
@ -7659,6 +7660,7 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
// [stack] CTOR? OBJ
|
||||
|
||||
size_t curFieldKeyIndex = 0;
|
||||
size_t curStaticFieldKeyIndex = 0;
|
||||
for (ParseNode* propdef : obj->contents()) {
|
||||
if (propdef->is<ClassField>()) {
|
||||
MOZ_ASSERT(type == ClassBody);
|
||||
|
|
@ -7666,7 +7668,9 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
// is created elsewhere.
|
||||
ClassField* field = &propdef->as<ClassField>();
|
||||
if (field->name().getKind() == PNK_COMPUTED_NAME) {
|
||||
if (!emitGetName(cx->names().dotFieldKeys)) {
|
||||
HandlePropertyName fieldKeys = field->isStatic() ? cx->names().dotStaticFieldKeys
|
||||
: cx->names().dotFieldKeys;
|
||||
if (!emitGetName(fieldKeys)) {
|
||||
// [stack] CTOR? OBJ ARRAY
|
||||
return false;
|
||||
}
|
||||
|
|
@ -7683,7 +7687,9 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!emitUint32Operand(JSOP_INITELEM_ARRAY, curFieldKeyIndex)) {
|
||||
size_t fieldKeysIndex = field->isStatic() ? curStaticFieldKeyIndex++
|
||||
: curFieldKeyIndex++;
|
||||
if (!emitUint32Operand(JSOP_INITELEM_ARRAY, fieldKeysIndex)) {
|
||||
// [stack] ARRAY
|
||||
return false;
|
||||
}
|
||||
|
|
@ -7692,8 +7698,6 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
// [stack] CTOR? OBJ
|
||||
return false;
|
||||
}
|
||||
|
||||
curFieldKeyIndex++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -7940,9 +7944,13 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
|
|||
}
|
||||
|
||||
FieldInitializers
|
||||
BytecodeEmitter::setupFieldInitializers(ListNode* classMembers)
|
||||
BytecodeEmitter::setupFieldInitializers(ListNode* classMembers, FieldPlacement placement)
|
||||
{
|
||||
size_t numFields = classMembers->count_if([](ParseNode* propdef) { return propdef->is<ClassField>(); });
|
||||
bool isStatic = placement == FieldPlacement::Static;
|
||||
size_t numFields = classMembers->count_if([isStatic](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>()&&
|
||||
propdef->as<ClassField>().isStatic() == isStatic;
|
||||
});
|
||||
|
||||
return FieldInitializers(numFields);
|
||||
}
|
||||
|
|
@ -7971,18 +7979,21 @@ BytecodeEmitter::setupFieldInitializers(ListNode* classMembers)
|
|||
// BytecodeEmitter::emitPropertyList fills in the elements of the array.
|
||||
// See Parser::fieldInitializer for the `this[.fieldKeys[0]]` part.
|
||||
bool
|
||||
BytecodeEmitter::emitCreateFieldKeys(ListNode* obj)
|
||||
BytecodeEmitter::emitCreateFieldKeys(ListNode* obj, FieldPlacement placement)
|
||||
{
|
||||
size_t numFieldKeys = obj->count_if([](ParseNode* propdef) {
|
||||
bool isStatic = placement == FieldPlacement::Static;
|
||||
size_t numFieldKeys = obj->count_if([isStatic](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>() &&
|
||||
propdef->as<ClassField>().isStatic() == isStatic &&
|
||||
propdef->as<ClassField>().name().getKind() == PNK_COMPUTED_NAME;
|
||||
});
|
||||
|
||||
if (numFieldKeys == 0)
|
||||
return true;
|
||||
|
||||
NameOpEmitter noe(this, cx->names().dotFieldKeys,
|
||||
NameOpEmitter::Kind::Initialize);
|
||||
HandlePropertyName fieldKeys = isStatic ? cx->names().dotStaticFieldKeys
|
||||
: cx->names().dotFieldKeys;
|
||||
NameOpEmitter noe(this, fieldKeys, NameOpEmitter::Kind::Initialize);
|
||||
if (!noe.prepareForRhs())
|
||||
return false;
|
||||
|
||||
|
|
@ -8005,45 +8016,64 @@ BytecodeEmitter::emitCreateFieldKeys(ListNode* obj)
|
|||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj)
|
||||
BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj,
|
||||
FieldPlacement placement)
|
||||
{
|
||||
// [stack] HOMEOBJ HERITAGE?
|
||||
FieldInitializers fieldInitializers = setupFieldInitializers(obj);
|
||||
// FieldPlacement::Instance
|
||||
// [stack] HOMEOBJ HERITAGE?
|
||||
//
|
||||
// FieldPlacement::Static
|
||||
// [stack] CTOR HOMEOBJ
|
||||
FieldInitializers fieldInitializers = setupFieldInitializers(obj, placement);
|
||||
MOZ_ASSERT(fieldInitializers.valid);
|
||||
size_t numFields = fieldInitializers.numFieldInitializers;
|
||||
|
||||
if (numFields == 0)
|
||||
return true;
|
||||
|
||||
if (!ce.prepareForFieldInitializers(numFields)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
bool isStatic = placement == FieldPlacement::Static;
|
||||
if (!ce.prepareForFieldInitializers(numFields, isStatic)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ParseNode* propdef : obj->contents()) {
|
||||
if (!propdef->is<ClassField>())
|
||||
if (!propdef->is<ClassField>() ||
|
||||
propdef->as<ClassField>().isStatic() != isStatic)
|
||||
continue;
|
||||
|
||||
FunctionNode* initializer = propdef->as<ClassField>().initializer();
|
||||
if (!ce.prepareForFieldInitializer())
|
||||
return false;
|
||||
if (!emitTree(initializer)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY LAMBDA
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ ARRAY LAMBDA
|
||||
return false;
|
||||
}
|
||||
if (initializer->funbox()->needsHomeObject()) {
|
||||
MOZ_ASSERT(initializer->funbox()->function()->allowSuperProperty());
|
||||
if (!ce.emitFieldInitializerHomeObject()) {
|
||||
if (!ce.emitFieldInitializerHomeObject(isStatic)) {
|
||||
// [stack] CTOR OBJ ARRAY LAMBDA
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ ARRAY LAMBDA
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!ce.emitStoreFieldInitializer()) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ ARRAY
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ce.emitFieldInitializersEnd()) {
|
||||
// [stack] HOMEOBJ HERITAGE?
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -8139,6 +8169,108 @@ BytecodeEmitter::emitInitializeInstanceFields()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::emitInitializeStaticFields(ListNode* classMembers)
|
||||
{
|
||||
size_t numFields = classMembers->count_if([](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>()&&
|
||||
propdef->as<ClassField>().isStatic();
|
||||
});
|
||||
|
||||
if (numFields == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!emitGetName(cx->names().dotStaticInitializers)) {
|
||||
// [stack] CTOR ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t fieldIndex = 0; fieldIndex < numFields; fieldIndex++) {
|
||||
bool hasNext = fieldIndex < numFields - 1;
|
||||
if (fieldIndex < numFields - 1) {
|
||||
// We DUP to keep the array around (it is consumed in the bytecode below)
|
||||
// for next iterations of this loop, except for the last iteration, which
|
||||
// avoids an extra POP at the end of the loop.
|
||||
if (!emit1(JSOP_DUP)) {
|
||||
// [stack] CTOR ARRAY ARRAY
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emitNumberOp(fieldIndex)) {
|
||||
// [stack] CTOR ARRAY? ARRAY INDEX
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't use CALLELEM here, because the receiver of the call != the receiver
|
||||
// of this getelem. (Specifically, the call receiver is `ctor`, and the
|
||||
// receiver of this getelem is `.staticInitializers`)
|
||||
if (!emit1(JSOP_GETELEM)) {
|
||||
// [stack] CTOR ARRAY? FUNC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitDupAt(1 + hasNext)) {
|
||||
// [stack] CTOR ARRAY? FUNC CTOR
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitCall(JSOP_CALL_IGNORES_RV, 0)) {
|
||||
// [stack] CTOR ARRAY? RVAL
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_POP)) {
|
||||
// [stack] CTOR ARRAY?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite |.staticInitializers| and |.staticFieldKeys| with undefined to
|
||||
// avoid keeping the arrays alive indefinitely.
|
||||
auto clearStaticFieldSlot = [&](HandlePropertyName name) {
|
||||
NameOpEmitter noe(this, name, NameOpEmitter::Kind::SimpleAssignment);
|
||||
if (!noe.prepareForRhs()) {
|
||||
// [stack] ENV? VAL?
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_UNDEFINED)) {
|
||||
// [stack] ENV? VAL? UNDEFINED
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!noe.emitAssignment()) {
|
||||
// [stack] VAL
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emit1(JSOP_POP)) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!clearStaticFieldSlot(cx->names().dotStaticInitializers))
|
||||
return false;
|
||||
|
||||
auto isStaticFieldWithComputedName = [](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>() &&
|
||||
propdef->as<ClassField>().isStatic() &&
|
||||
propdef->as<ClassField>().name().getKind() == PNK_COMPUTED_NAME;
|
||||
};
|
||||
|
||||
if (classMembers->any_of(isStaticFieldWithComputedName)) {
|
||||
if (!clearStaticFieldSlot(cx->names().dotStaticFieldKeys))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Using MOZ_NEVER_INLINE in here is a workaround for llvm.org/pr14047. See
|
||||
// the comment on emitSwitch.
|
||||
MOZ_NEVER_INLINE bool
|
||||
|
|
@ -8684,15 +8816,17 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
// As an optimization omit the |.initializers| binding when no instance
|
||||
// fields are present.
|
||||
bool hasInstanceFields = classMembers->any_of([](ParseNode* propdef) {
|
||||
return propdef->is<ClassField>();
|
||||
});
|
||||
return propdef->is<ClassField>() &&
|
||||
!propdef->as<ClassField>().isStatic();
|
||||
});
|
||||
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))
|
||||
if (!emitCreateFieldInitializers(ce, classMembers,
|
||||
FieldPlacement::Instance))
|
||||
return false;
|
||||
}
|
||||
ctor = &constructorScope->scopeBody()->as<ClassMethod>().method();
|
||||
|
|
@ -8726,7 +8860,13 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
}
|
||||
}
|
||||
|
||||
if (!emitCreateFieldKeys(classMembers))
|
||||
if (!emitCreateFieldKeys(classMembers, FieldPlacement::Instance))
|
||||
return false;
|
||||
|
||||
if (!emitCreateFieldInitializers(ce, classMembers, FieldPlacement::Static))
|
||||
return false;
|
||||
|
||||
if (!emitCreateFieldKeys(classMembers, FieldPlacement::Static))
|
||||
return false;
|
||||
|
||||
if (!emitPropertyList(classMembers, ce, ClassBody)) {
|
||||
|
|
@ -8734,6 +8874,16 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!ce.emitBinding()) {
|
||||
// [stack] CTOR
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitInitializeStaticFields(classMembers)) {
|
||||
// [stack] CTOR
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ce.emitEnd(kind)) {
|
||||
// [stack] # class declaration
|
||||
// [stack]
|
||||
|
|
|
|||
|
|
@ -530,11 +530,13 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitPropertyList(ListNode* obj, PropertyEmitter& pe,
|
||||
PropListType type);
|
||||
|
||||
FieldInitializers setupFieldInitializers(ListNode* classMembers);
|
||||
MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj);
|
||||
MOZ_MUST_USE bool emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj);
|
||||
enum class FieldPlacement { Instance, Static };
|
||||
FieldInitializers setupFieldInitializers(ListNode* classMembers, FieldPlacement placement);
|
||||
MOZ_MUST_USE bool emitCreateFieldKeys(ListNode* obj, FieldPlacement placement);
|
||||
MOZ_MUST_USE bool emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj, FieldPlacement placement);
|
||||
const FieldInitializers& findFieldInitializersForCall();
|
||||
MOZ_MUST_USE bool emitInitializeInstanceFields();
|
||||
MOZ_MUST_USE bool emitInitializeStaticFields(ListNode* classMembers);
|
||||
|
||||
// To catch accidental misuse, emitUint16Operand/emit3 assert that they are
|
||||
// not used to unconditionally emit JSOP_GETLOCAL. Variable access should
|
||||
|
|
|
|||
|
|
@ -467,11 +467,11 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
|||
return new_<ClassMethod>(key, funNode, op, isStatic);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE ClassField* newClassFieldDefinition(Node name, FunctionNodeType initializer)
|
||||
MOZ_MUST_USE ClassField* newClassFieldDefinition(Node name, FunctionNodeType initializer, bool isStatic)
|
||||
{
|
||||
MOZ_ASSERT(isUsableAsObjectPropertyName(name));
|
||||
|
||||
return new_<ClassField>(name, initializer);
|
||||
return new_<ClassField>(name, initializer, isStatic);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member)
|
||||
|
|
|
|||
|
|
@ -484,51 +484,79 @@ bool ObjectEmitter::emitObject(size_t propertyCount)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::prepareForFieldInitializers(size_t numFields)
|
||||
bool ClassEmitter::prepareForFieldInitializers(size_t numFields, bool isStatic)
|
||||
{
|
||||
MOZ_ASSERT(classState_ == ClassState::Class);
|
||||
MOZ_ASSERT_IF(!isStatic, classState_ == ClassState::Class);
|
||||
MOZ_ASSERT_IF(isStatic, classState_ == ClassState::InitConstructor);
|
||||
MOZ_ASSERT(fieldState_ == FieldState::Start);
|
||||
|
||||
// .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,
|
||||
HandlePropertyName initializers = isStatic ? bce_->cx->names().dotStaticInitializers
|
||||
: bce_->cx->names().dotInitializers;
|
||||
initializersAssignment_.emplace(bce_, initializers,
|
||||
NameOpEmitter::Kind::Initialize);
|
||||
if (!initializersAssignment_->prepareForRhs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bce_->emitUint32Operand(JSOP_NEWARRAY, numFields)) {
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY
|
||||
// [stack] ARRAY
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(fieldIndex_ == 0);
|
||||
fieldIndex_ = 0;
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::FieldInitializers;
|
||||
if (isStatic) {
|
||||
classState_ = ClassState::StaticFieldInitializers;
|
||||
} else {
|
||||
classState_ = ClassState::InstanceFieldInitializers;
|
||||
}
|
||||
numFields_ = numFields;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitFieldInitializerHomeObject()
|
||||
bool ClassEmitter::prepareForFieldInitializer()
|
||||
{
|
||||
MOZ_ASSERT(classState_ == ClassState::FieldInitializers);
|
||||
// [stack] OBJ HERITAGE? ARRAY METHOD
|
||||
if (!bce_->emit2(JSOP_INITHOMEOBJECT, isDerived_ ? 2 : 1)) {
|
||||
// [stack] OBJ HERITAGE? ARRAY METHOD
|
||||
MOZ_ASSERT(classState_ == ClassState::InstanceFieldInitializers ||
|
||||
classState_ == ClassState::StaticFieldInitializers);
|
||||
MOZ_ASSERT(fieldState_ == FieldState::Start);
|
||||
|
||||
#ifdef DEBUG
|
||||
fieldState_ = FieldState::Initializer;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitFieldInitializerHomeObject(bool isStatic)
|
||||
{
|
||||
MOZ_ASSERT(fieldState_ == FieldState::Initializer);
|
||||
// [stack] OBJ HERITAGE? ARRAY METHOD
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ ARRAY METHOD
|
||||
uint8_t ofs = isStatic ? 2
|
||||
// [stack] CTOR HOMEOBJ ARRAY METHOD CTOR
|
||||
: isDerived_ ? 2 : 1;
|
||||
// [stack] OBJ HERITAGE? ARRAY METHOD OBJ
|
||||
if (!bce_->emit2(JSOP_INITHOMEOBJECT, ofs)) {
|
||||
// [stack] OBJ HERITAGE? ARRAY METHOD
|
||||
// or:
|
||||
// [stack] CTOR HOMEOBJ ARRAY METHOD
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::FieldInitializerWithHomeObject;
|
||||
fieldState_ = FieldState::InitializerWithHomeObject;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitStoreFieldInitializer()
|
||||
{
|
||||
MOZ_ASSERT(classState_ == ClassState::FieldInitializers ||
|
||||
classState_ == ClassState::FieldInitializerWithHomeObject);
|
||||
MOZ_ASSERT(fieldState_ == FieldState::Initializer ||
|
||||
fieldState_ == FieldState::InitializerWithHomeObject);
|
||||
MOZ_ASSERT(fieldIndex_ < numFields_);
|
||||
// [stack] HOMEOBJ HERITAGE? ARRAY METHOD
|
||||
|
||||
|
|
@ -539,7 +567,7 @@ bool ClassEmitter::emitStoreFieldInitializer()
|
|||
|
||||
fieldIndex_++;
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::FieldInitializers;
|
||||
fieldState_ = FieldState::Start;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -548,8 +576,9 @@ bool ClassEmitter::emitFieldInitializersEnd()
|
|||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start ||
|
||||
propertyState_ == PropertyState::Init);
|
||||
MOZ_ASSERT(classState_ == ClassState::FieldInitializers ||
|
||||
classState_ == ClassState::FieldInitializerWithHomeObject);
|
||||
MOZ_ASSERT(classState_ == ClassState::InstanceFieldInitializers ||
|
||||
classState_ == ClassState::StaticFieldInitializers);
|
||||
MOZ_ASSERT(fieldState_ == FieldState::Start);
|
||||
MOZ_ASSERT(fieldIndex_ == numFields_);
|
||||
|
||||
if (!initializersAssignment_->emitAssignment()) {
|
||||
|
|
@ -564,7 +593,11 @@ bool ClassEmitter::emitFieldInitializersEnd()
|
|||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::FieldInitializersEnd;
|
||||
if (classState_ == ClassState::InstanceFieldInitializers) {
|
||||
classState_ = ClassState::InstanceFieldInitializersEnd;
|
||||
} else {
|
||||
classState_ = ClassState::StaticFieldInitializersEnd;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
@ -700,7 +733,7 @@ bool ClassEmitter::emitInitConstructor(bool needsHomeObject)
|
|||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class ||
|
||||
classState_ == ClassState::FieldInitializersEnd);
|
||||
classState_ == ClassState::InstanceFieldInitializersEnd);
|
||||
|
||||
// [stack] HOMEOBJ CTOR
|
||||
|
||||
|
|
@ -726,8 +759,7 @@ bool ClassEmitter::emitInitDefaultConstructor(const Maybe<uint32_t>& classStart,
|
|||
const Maybe<uint32_t>& classEnd)
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class ||
|
||||
classState_ == ClassState::FieldInitializersEnd);
|
||||
MOZ_ASSERT(classState_ == ClassState::Class);
|
||||
|
||||
if (classStart && classEnd) {
|
||||
// In the case of default class constructors, emit the start and end
|
||||
|
|
@ -789,12 +821,13 @@ bool ClassEmitter::initProtoAndCtor()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ClassEmitter::emitEnd(Kind kind)
|
||||
bool ClassEmitter::emitBinding()
|
||||
{
|
||||
MOZ_ASSERT(propertyState_ == PropertyState::Start ||
|
||||
propertyState_ == PropertyState::Init);
|
||||
MOZ_ASSERT(classState_ == ClassState::InitConstructor ||
|
||||
classState_ == ClassState::FieldInitializersEnd);
|
||||
classState_ == ClassState::InstanceFieldInitializersEnd ||
|
||||
classState_ == ClassState::StaticFieldInitializersEnd);
|
||||
|
||||
// [stack] CTOR HOMEOBJ
|
||||
|
||||
|
|
@ -804,49 +837,54 @@ bool ClassEmitter::emitEnd(Kind kind)
|
|||
}
|
||||
|
||||
if (name_ != bce_->cx->names().empty) {
|
||||
MOZ_ASSERT(tdzCache_.isSome());
|
||||
MOZ_ASSERT(innerScope_.isSome());
|
||||
|
||||
if (!bce_->emitLexicalInitialization(name_)) {
|
||||
// [stack] CTOR
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Pop the inner scope.
|
||||
if (!innerScope_->leave(bce_))
|
||||
return false;
|
||||
innerScope_.reset();
|
||||
// [stack] CTOR
|
||||
|
||||
if (kind == Kind::Declaration) {
|
||||
if (!bce_->emitLexicalInitialization(name_)) {
|
||||
// [stack] CTOR
|
||||
return false;
|
||||
}
|
||||
// Only class statements make outer bindings, and they do not leave
|
||||
// themselves on the stack.
|
||||
if (!bce_->emit1(JSOP_POP)) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
classState_ = ClassState::BoundName;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
tdzCache_.reset();
|
||||
} else if (innerScope_.isSome()) {
|
||||
// [stack] CTOR
|
||||
MOZ_ASSERT(kind == Kind::Expression);
|
||||
bool ClassEmitter::emitEnd(Kind kind)
|
||||
{
|
||||
MOZ_ASSERT(classState_ == ClassState::BoundName);
|
||||
// [stack] CTOR
|
||||
|
||||
if (innerScope_.isSome()) {
|
||||
MOZ_ASSERT(tdzCache_.isSome());
|
||||
|
||||
if (!innerScope_->leave(bce_))
|
||||
return false;
|
||||
innerScope_.reset();
|
||||
tdzCache_.reset();
|
||||
}else {
|
||||
// [stack] CTOR
|
||||
|
||||
} else {
|
||||
MOZ_ASSERT(kind == Kind::Expression);
|
||||
MOZ_ASSERT(tdzCache_.isNothing());
|
||||
}
|
||||
|
||||
if (kind == Kind::Declaration) {
|
||||
MOZ_ASSERT(name_);
|
||||
|
||||
if (!bce_->emitLexicalInitialization(name_)) {
|
||||
// [stack] CTOR
|
||||
return false;
|
||||
}
|
||||
// Only class statements make outer bindings, and they do not leave
|
||||
// themselves on the stack.
|
||||
if (!bce_->emit1(JSOP_POP)) {
|
||||
// [stack]
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// [stack] # class declaration
|
||||
// [stack]
|
||||
// [stack] # class expression
|
||||
|
|
|
|||
|
|
@ -685,30 +685,20 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
// |
|
||||
// +-------------------------------+
|
||||
// |
|
||||
// | prepareForFieldInitializers
|
||||
// +-----------------------------+
|
||||
// | |
|
||||
// | | +-------------------+
|
||||
// | +--------------------->+--->| FieldInitializers |-+
|
||||
// | | +-------------------+ |
|
||||
// | | |
|
||||
// | | (emit initializer method) |
|
||||
// | | +<--------------------------------------------+
|
||||
// | | |
|
||||
// | | | emitFieldInitializerHomeObject +--------------------------------+
|
||||
// | | +-------------------------------->| FieldInitializerWithHomeObject |-+
|
||||
// | | | +--------------------------------+ |
|
||||
// | | | |
|
||||
// | | +------------------------------------------------------------------->+
|
||||
// | | |
|
||||
// | | emitStoreFieldInitializer |
|
||||
// | +<--+<-----------------------------------------------------------------------+
|
||||
// | |
|
||||
// | | emitFieldInitializersEnd +----------------------+
|
||||
// | +-------------------------->| FieldInitializersEnd |-+
|
||||
// | +----------------------+ |
|
||||
// | |
|
||||
// |<------------------------------------------------------+
|
||||
// | prepareForFieldInitializers(isStatic = false)
|
||||
// +---------------+
|
||||
// | |
|
||||
// | +--------v------------------+
|
||||
// | | InstanceFieldInitializers |
|
||||
// | +---------------------------+
|
||||
// | |
|
||||
// | emitFieldInitializersEnd
|
||||
// | |
|
||||
// | +--------v---------------------+
|
||||
// | | InstanceFieldInitializersEnd |
|
||||
// | +------------------------------+
|
||||
// | |
|
||||
// +<--------------+
|
||||
// |
|
||||
// |
|
||||
// | emitInitConstructor +-----------------+
|
||||
|
|
@ -717,11 +707,36 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
// | emitInitDefaultConstructor | |
|
||||
// +----------------------------+ |
|
||||
// |
|
||||
// +---------------------------------------------------+
|
||||
// |
|
||||
// | (do PropertyEmitter operation) emitEnd +-----+
|
||||
// +-------------------------------+--------->| End |
|
||||
// +-----+
|
||||
// +-----------------------------------------------------+
|
||||
// |
|
||||
// | prepareForFieldInitializers(isStatic = true)
|
||||
// +---------------+
|
||||
// | |
|
||||
// | +--------v----------------+
|
||||
// | | StaticFieldInitializers |
|
||||
// | +-------------------------+
|
||||
// | |
|
||||
// | | emitFieldInitializersEnd
|
||||
// | |
|
||||
// | +--------v-------------------+
|
||||
// | | StaticFieldInitializersEnd |
|
||||
// | +----------------------------+
|
||||
// | |
|
||||
// +<--------------+
|
||||
// |
|
||||
// | (do PropertyEmitter operation)
|
||||
// +--------------------------------+
|
||||
// |
|
||||
// +-------------+ emitBinding |
|
||||
// | BoundName |<-----------------+
|
||||
// +--+----------+
|
||||
// |
|
||||
// | emitEnd
|
||||
// |
|
||||
// +--v----+
|
||||
// | End |
|
||||
// +-------+
|
||||
//
|
||||
enum class ClassState {
|
||||
// The initial state.
|
||||
Start,
|
||||
|
|
@ -735,20 +750,60 @@ class MOZ_STACK_CLASS ClassEmitter : public PropertyEmitter
|
|||
// After calling emitInitConstructor or emitInitDefaultConstructor.
|
||||
InitConstructor,
|
||||
|
||||
// After calling prepareForFieldInitializers
|
||||
// and 0 or more calls to emitStoreFieldInitializer.
|
||||
FieldInitializers,
|
||||
|
||||
// After calling emitFieldInitializerHomeObject
|
||||
FieldInitializerWithHomeObject,
|
||||
// After calling prepareForFieldInitializers(isStatic = false).
|
||||
InstanceFieldInitializers,
|
||||
|
||||
// After calling emitFieldInitializersEnd.
|
||||
FieldInitializersEnd,
|
||||
InstanceFieldInitializersEnd,
|
||||
|
||||
// After calling prepareForFieldInitializers(isStatic = true).
|
||||
StaticFieldInitializers,
|
||||
|
||||
// After calling emitFieldInitializersEnd.
|
||||
StaticFieldInitializersEnd,
|
||||
|
||||
// After calling emitBinding.
|
||||
BoundName,
|
||||
|
||||
// After calling emitEnd.
|
||||
End,
|
||||
};
|
||||
ClassState classState_ = ClassState::Start;
|
||||
|
||||
// The state of the fields emitter.
|
||||
//
|
||||
// clang-format off
|
||||
//
|
||||
// +-------+
|
||||
// | Start +<-----------------------------+
|
||||
// +-------+ |
|
||||
// | |
|
||||
// | prepareForFieldInitializer | emitStoreFieldInitializer
|
||||
// v |
|
||||
// +-------------+ |
|
||||
// | Initializer +------------------------->+
|
||||
// +-------------+ |
|
||||
// | |
|
||||
// | emitFieldInitializerHomeObject |
|
||||
// v |
|
||||
// +---------------------------+ |
|
||||
// | InitializerWithHomeObject +------------+
|
||||
// +---------------------------+
|
||||
//
|
||||
// clang-format on
|
||||
enum class FieldState {
|
||||
// After calling prepareForFieldInitializers
|
||||
// and 0 or more calls to emitStoreFieldInitializer.
|
||||
Start,
|
||||
|
||||
// After calling prepareForFieldInitializer
|
||||
Initializer,
|
||||
|
||||
// After calling emitFieldInitializerHomeObject
|
||||
InitializerWithHomeObject,
|
||||
};
|
||||
FieldState fieldState_ = FieldState::Start;
|
||||
|
||||
size_t numFields_ = 0;
|
||||
#endif
|
||||
|
||||
|
|
@ -783,11 +838,14 @@ 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 emitFieldInitializerHomeObject();
|
||||
MOZ_MUST_USE bool prepareForFieldInitializers(size_t numFields, bool isStatic);
|
||||
MOZ_MUST_USE bool prepareForFieldInitializer();
|
||||
MOZ_MUST_USE bool emitFieldInitializerHomeObject(bool isStatic);
|
||||
MOZ_MUST_USE bool emitStoreFieldInitializer();
|
||||
MOZ_MUST_USE bool emitFieldInitializersEnd();
|
||||
|
||||
MOZ_MUST_USE bool emitBinding();
|
||||
|
||||
MOZ_MUST_USE bool emitEnd(Kind kind);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -761,6 +761,7 @@ class ParseNode
|
|||
private:
|
||||
friend class BinaryNode;
|
||||
friend class ForNode;
|
||||
friend class ClassField;
|
||||
friend class ClassMethod;
|
||||
friend class PropertyAccessBase;
|
||||
friend class SwitchStatement;
|
||||
|
|
@ -768,7 +769,7 @@ class ParseNode
|
|||
ParseNode* right;
|
||||
union {
|
||||
unsigned iflags; /* JSITER_* flags for PNK_{COMPREHENSION,}FOR node */
|
||||
bool isStatic; /* only for PNK_CLASSMETHOD */
|
||||
bool isStatic; /* only for PNK_CLASSMETHOD and PNK_CLASSFIELD */
|
||||
bool hasDefault; /* only for PNK_SWITCH */
|
||||
};
|
||||
} binary;
|
||||
|
|
@ -785,12 +786,6 @@ class ParseNode
|
|||
ParseNode* initOrStmt; /* var initializer, argument default,
|
||||
* or label statement target */
|
||||
} name;
|
||||
struct {
|
||||
private:
|
||||
friend class ClassField;
|
||||
ParseNode* name;
|
||||
ParseNode* initializer; /* field initializer - optional */
|
||||
} field;
|
||||
struct {
|
||||
private:
|
||||
friend class RegExpLiteral;
|
||||
|
|
@ -2141,11 +2136,12 @@ class ClassMethod : public BinaryNode
|
|||
class ClassField : public BinaryNode
|
||||
{
|
||||
public:
|
||||
ClassField(ParseNode* name, ParseNode* initializer)
|
||||
ClassField(ParseNode* name, ParseNode* initializer, bool isStatic)
|
||||
: BinaryNode(PNK_CLASSFIELD, JSOP_NOP,
|
||||
TokenPos::box(name->pn_pos, initializer->pn_pos),
|
||||
name, initializer)
|
||||
{
|
||||
pn_u.binary.isStatic = isStatic;
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
|
|
@ -2157,6 +2153,10 @@ class ClassField : public BinaryNode
|
|||
ParseNode& name() const { return *left(); }
|
||||
|
||||
FunctionNode* initializer() const { return &right()->as<FunctionNode>(); }
|
||||
|
||||
bool isStatic() const {
|
||||
return pn_u.binary.isStatic;
|
||||
}
|
||||
};
|
||||
|
||||
class SwitchStatement : public BinaryNode
|
||||
|
|
|
|||
|
|
@ -7419,7 +7419,7 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling,
|
|||
const ParseContext::ClassStatement& classStmt,
|
||||
HandlePropertyName className,
|
||||
uint32_t classStartOffset, bool hasHeritage,
|
||||
size_t& numFields, size_t& numFieldKeys,
|
||||
ClassFields& classFields,
|
||||
ListNodeType& classMembers, bool* done)
|
||||
{
|
||||
*done = false;
|
||||
|
|
@ -7474,8 +7474,10 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling,
|
|||
}
|
||||
|
||||
if (isStatic) {
|
||||
errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
|
||||
return false;
|
||||
if (propAtom == context->names().prototype) {
|
||||
errorAt(propNameOffset, JSMSG_BAD_METHOD_DEF);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (propAtom == context->names().constructor) {
|
||||
|
|
@ -7486,9 +7488,13 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling,
|
|||
if (!abortIfSyntaxParser())
|
||||
return false;
|
||||
|
||||
numFields++;
|
||||
if (isStatic) {
|
||||
classFields.staticFields++;
|
||||
} else {
|
||||
classFields.instanceFields++;
|
||||
}
|
||||
|
||||
FunctionNodeType initializer = fieldInitializerOpt(propAtom, numFieldKeys);
|
||||
FunctionNodeType initializer = fieldInitializerOpt(propAtom, classFields, isStatic);
|
||||
if (!initializer)
|
||||
return false;
|
||||
|
||||
|
|
@ -7496,7 +7502,7 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling,
|
|||
return false;
|
||||
}
|
||||
|
||||
ClassFieldType field = handler.newClassFieldDefinition(propName, initializer);
|
||||
ClassFieldType field = handler.newClassFieldDefinition(propName, initializer, isStatic);
|
||||
if (!field)
|
||||
return false;
|
||||
|
||||
|
|
@ -7613,12 +7619,12 @@ bool
|
|||
Parser<ParseHandler>::finishClassConstructor(const ParseContext::ClassStatement& classStmt,
|
||||
HandlePropertyName className, bool hasHeritage,
|
||||
uint32_t classStartOffset, uint32_t classEndOffset,
|
||||
size_t numFields,
|
||||
ListNodeType& classMembers)
|
||||
const ClassFields& classFields, ListNodeType& classMembers)
|
||||
{
|
||||
// Fields cannot re-use the constructor obtained via JSOP_CLASSCONSTRUCTOR or
|
||||
// JSOP_DERIVEDCONSTRUCTOR due to needing to emit calls to the field
|
||||
// initializers in the constructor. So, synthesize a new one.
|
||||
size_t numFields = classFields.instanceFields;
|
||||
if (classStmt.constructorBox == nullptr && numFields > 0) {
|
||||
MOZ_ASSERT(!options().selfHostingMode);
|
||||
// Unconditionally create the scope here, because it's always the
|
||||
|
|
@ -7755,24 +7761,36 @@ Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
|
|||
if (!classMembers)
|
||||
return null();
|
||||
|
||||
size_t numFields = 0;
|
||||
size_t numFieldKeys = 0;
|
||||
ClassFields classFields{};
|
||||
for (;;) {
|
||||
bool done;
|
||||
if (!classMember(yieldHandling, classStmt, className, classStartOffset,
|
||||
hasHeritage, numFields, numFieldKeys, classMembers, &done))
|
||||
if (!classMember(yieldHandling, classStmt, className, classStartOffset, hasHeritage,
|
||||
classFields, classMembers, &done))
|
||||
return null();
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
|
||||
if (numFieldKeys > 0) {
|
||||
if (classFields.instanceFieldKeys > 0) {
|
||||
if (!noteDeclaredName(context->names().dotFieldKeys, DeclarationKind::Let, namePos))
|
||||
return null();
|
||||
}
|
||||
|
||||
if (classFields.staticFields > 0) {
|
||||
if (!noteDeclaredName(context->names().dotStaticInitializers,
|
||||
DeclarationKind::Let, namePos))
|
||||
return null();
|
||||
}
|
||||
|
||||
if (classFields.staticFieldKeys > 0) {
|
||||
if (!noteDeclaredName(context->names().dotStaticFieldKeys,
|
||||
DeclarationKind::Let, namePos))
|
||||
return null();
|
||||
}
|
||||
|
||||
classEndOffset = pos().end;
|
||||
if (!finishClassConstructor(classStmt, className, hasHeritage,
|
||||
classStartOffset, classEndOffset, numFields, classMembers))
|
||||
classStartOffset, classEndOffset, classFields, classMembers))
|
||||
return null();
|
||||
|
||||
if (className) {
|
||||
|
|
@ -7954,7 +7972,7 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
|
|||
|
||||
template <class ParseHandler>
|
||||
typename ParseHandler::FunctionNodeType
|
||||
Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldKeys)
|
||||
Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& classFields, bool isStatic)
|
||||
{
|
||||
bool hasInitializer = false;
|
||||
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
|
||||
|
|
@ -8052,17 +8070,18 @@ Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, size_t& numFieldK
|
|||
if (!propAtom) {
|
||||
// See BytecodeEmitter::emitCreateFieldKeys for an explanation of what
|
||||
// .fieldKeys means and its purpose.
|
||||
Node dotFieldKeys = newInternalDotName(context->names().dotFieldKeys);
|
||||
if (!dotFieldKeys)
|
||||
NameNodeType fieldKeysName = newInternalDotName(isStatic ? context->names().dotStaticFieldKeys
|
||||
: context->names().dotFieldKeys);
|
||||
if (!fieldKeysName)
|
||||
return null();
|
||||
|
||||
double fieldKeyIndex = numFieldKeys;
|
||||
numFieldKeys++;
|
||||
double fieldKeyIndex = isStatic ? classFields.staticFieldKeys++
|
||||
: classFields.instanceFieldKeys++;
|
||||
Node fieldKeyIndexNode = handler.newNumber(fieldKeyIndex, DecimalPoint::NoDecimal, wholeInitializerPos);
|
||||
if (!fieldKeyIndexNode)
|
||||
return null();
|
||||
|
||||
Node fieldKeyValue = handler.newPropertyByValue(dotFieldKeys, fieldKeyIndexNode, wholeInitializerPos.end);
|
||||
Node fieldKeyValue = handler.newPropertyByValue(fieldKeysName, fieldKeyIndexNode, wholeInitializerPos.end);
|
||||
if (!fieldKeyValue)
|
||||
return null();
|
||||
|
||||
|
|
|
|||
|
|
@ -1488,20 +1488,32 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
|||
enum ClassContext { ClassStatement, ClassExpression };
|
||||
ClassNodeType classDefinition(YieldHandling yieldHandling, ClassContext classContext,
|
||||
DefaultHandling defaultHandling);
|
||||
struct ClassFields {
|
||||
// The number of instance class fields.
|
||||
size_t instanceFields = 0;
|
||||
|
||||
// The number of instance class fields with computed property names.
|
||||
size_t instanceFieldKeys = 0;
|
||||
|
||||
// The number of static class fields.
|
||||
size_t staticFields = 0;
|
||||
|
||||
// The number of static class fields with computed property names.
|
||||
size_t staticFieldKeys = 0;
|
||||
};
|
||||
MOZ_MUST_USE bool classMember(YieldHandling yieldHandling,
|
||||
const ParseContext::ClassStatement& classStmt,
|
||||
HandlePropertyName className,
|
||||
uint32_t classStartOffset, bool hasHeritage,
|
||||
size_t& numFields,
|
||||
size_t& numFieldKeys,
|
||||
ClassFields& classFields,
|
||||
ListNodeType& classMembers, bool* done);
|
||||
MOZ_MUST_USE bool finishClassConstructor(
|
||||
const ParseContext::ClassStatement& classStmt,
|
||||
HandlePropertyName className, bool hasHeritage,
|
||||
uint32_t classStartOffset, uint32_t classEndOffset,
|
||||
size_t numFieldsWithInitializers, ListNodeType& classMembers);
|
||||
const ClassFields& classFields, ListNodeType& classMembers);
|
||||
|
||||
FunctionNodeType fieldInitializerOpt(HandleAtom atom, size_t& numFieldKeys);
|
||||
FunctionNodeType fieldInitializerOpt(HandleAtom atom, ClassFields& classFields, bool isStatic);
|
||||
FunctionNodeType synthesizeConstructor(HandleAtom className,
|
||||
uint32_t classNameOffset,
|
||||
bool hasHeritage);
|
||||
|
|
|
|||
|
|
@ -332,7 +332,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
|||
MOZ_MUST_USE bool addSpreadProperty(ListNodeType literal, uint32_t begin, Node inner) { return true; }
|
||||
MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node name, FunctionNodeType funNode, JSOp op) { return true; }
|
||||
MOZ_MUST_USE Node newClassMethodDefinition(Node key, FunctionNodeType funNode, JSOp op, bool isStatic) { return NodeGeneric; }
|
||||
MOZ_MUST_USE Node newClassFieldDefinition(Node name, FunctionNodeType initializer) { return NodeGeneric; }
|
||||
MOZ_MUST_USE Node newClassFieldDefinition(Node name, FunctionNodeType initializer, bool isStatic) { return NodeGeneric; }
|
||||
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member) { return true; }
|
||||
UnaryNodeType newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@
|
|||
macro(dotThis, dotThis, ".this") \
|
||||
macro(dotInitializers, dotInitializers, ".initializers") \
|
||||
macro(dotFieldKeys, dotFieldKeys, ".fieldKeys") \
|
||||
macro(dotStaticInitializers, dotStaticInitializers, ".staticInitializers") \
|
||||
macro(dotStaticFieldKeys, dotStaticFieldKeys, ".staticFieldKeys") \
|
||||
macro(each, each, "each") \
|
||||
macro(elementType, elementType, "elementType") \
|
||||
macro(else, else_, "else") \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue