diff options
Diffstat (limited to 'js/src/frontend/BytecodeEmitter.cpp')
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 255 |
1 files changed, 157 insertions, 98 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index df44743768..2759fa5924 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -925,6 +925,7 @@ restart: // Watch out for getters! case ParseNodeKind::OptionalDotExpr: case ParseNodeKind::DotExpr: + case ParseNodeKind::ArgumentsLength: MOZ_ASSERT(pn->is<BinaryNode>()); *answer = true; return true; @@ -2601,6 +2602,7 @@ bool BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, *emitted = 0; break; + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &target->as<PropertyAccess>(); bool isSuper = prop->isSuper(); @@ -2760,6 +2762,7 @@ bool BytecodeEmitter::emitSetOrInitializeDestructuring( break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { // The reference is already pushed by emitDestructuringLHSRef. // [stack] # if Super @@ -4367,6 +4370,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs, : NameOpEmitter::Kind::SimpleAssignment); break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &lhs->as<PropertyAccess>(); bool isSuper = prop->isSuper(); @@ -4466,6 +4470,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs, if (isCompound) { MOZ_ASSERT(rhs); switch (lhs->getKind()) { + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &lhs->as<PropertyAccess>(); if (!poe->emitGet(prop->key().atom())) { @@ -4512,6 +4517,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs, } offset += noe->emittedBindOp(); break; + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: if (!poe->prepareForRhs()) { // [stack] # if Simple Assignment with Super @@ -4579,6 +4585,7 @@ bool BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, ParseNode* lhs, } break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &lhs->as<PropertyAccess>(); if (!poe->emitAssignment(prop->key().atom())) { @@ -4666,7 +4673,7 @@ bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) { numPushed = noe->emittedBindOp(); break; } - + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &lhs->as<PropertyAccess>(); bool isSuper = prop->isSuper(); @@ -4802,7 +4809,7 @@ bool BytecodeEmitter::emitShortCircuitAssignment(AssignmentNode* node) { } break; } - + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &lhs->as<PropertyAccess>(); @@ -7326,6 +7333,7 @@ bool BytecodeEmitter::emitDeleteOptionalChain(UnaryNode* deleteNode) { break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: case ParseNodeKind::OptionalDotExpr: { auto* propExpr = &kid->as<PropertyAccessBase>(); @@ -7978,6 +7986,7 @@ bool BytecodeEmitter::emitOptionalCalleeAndThis(ParseNode* callee, } break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting); PropertyAccess* prop = &callee->as<PropertyAccess>(); @@ -8076,6 +8085,7 @@ bool BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, CallNode* maybeCall, } break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting); PropertyAccess* prop = &callee->as<PropertyAccess>(); @@ -8197,6 +8207,7 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* callNode, coordNode = argsList; switch (calleeNode->getKind()) { + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: // Use the position of a property access identifier. // @@ -8658,6 +8669,7 @@ bool BytecodeEmitter::emitOptionalTree( } break; } + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: { PropertyAccess* prop = &pn->as<PropertyAccess>(); bool isSuper = prop->isSuper(); @@ -9015,6 +9027,7 @@ bool BytecodeEmitter::emitSequenceExpr(ListNode* node, ValueUsage valueUsage) { MOZ_NEVER_INLINE bool BytecodeEmitter::emitIncOrDec(UnaryNode* incDec, ValueUsage valueUsage) { switch (incDec->kid()->getKind()) { + case ParseNodeKind::ArgumentsLength: case ParseNodeKind::DotExpr: return emitPropIncDec(incDec, valueUsage); case ParseNodeKind::ElemExpr: @@ -9859,6 +9872,12 @@ static bool NeedsPrivateBrand(ParseNode* member) { !member->as<ClassMethod>().isStatic(); } +#ifdef ENABLE_DECORATORS +static bool HasDecorators(ParseNode* member) { + return member->is<ClassMethod>() && member->as<ClassMethod>().decorators(); +} +#endif + mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers( ListNode* classMembers, FieldPlacement placement) { bool isStatic = placement == FieldPlacement::Static; @@ -9866,6 +9885,9 @@ mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers( size_t numFields = 0; size_t numPrivateInitializers = 0; bool hasPrivateBrand = false; +#ifdef ENABLE_DECORATORS + bool hasDecorators = false; +#endif for (ParseNode* member : classMembers->contents()) { if (NeedsFieldInitializer(member, isStatic)) { numFields++; @@ -9875,6 +9897,11 @@ mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers( } else if (NeedsPrivateBrand(member)) { hasPrivateBrand = true; } +#ifdef ENABLE_DECORATORS + if (!hasDecorators && HasDecorators(member)) { + hasDecorators = true; + } +#endif } // If there are more initializers than can be represented, return invalid. @@ -9882,8 +9909,11 @@ mozilla::Maybe<MemberInitializers> BytecodeEmitter::setupMemberInitializers( MemberInitializers::MaxInitializers) { return Nothing(); } - return Some( - MemberInitializers(hasPrivateBrand, numFields + numPrivateInitializers)); + return Some(MemberInitializers(hasPrivateBrand, +#ifdef ENABLE_DECORATORS + hasDecorators, +#endif + numFields + numPrivateInitializers)); } // Purpose of .fieldKeys: @@ -10691,119 +10721,122 @@ bool BytecodeEmitter::emitInitializeInstanceMembers( } } #ifdef ENABLE_DECORATORS - // Decorators Proposal - // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements - // 4. For each element e of elements, do - // 4.a. If elementRecord.[[Kind]] is field or accessor, then - // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord). - // + if (memberInitializers.hasDecorators) { + // Decorators Proposal + // https://arai-a.github.io/ecma262-compare/?pr=2417&id=sec-initializeinstanceelements + // 4. For each element e of elements, do + // 4.a. If elementRecord.[[Kind]] is field or accessor, then + // 4.a.i. Perform ? InitializeFieldOrAccessor(O, elementRecord). + // - // TODO: (See Bug 1817993) At the moment, we're applying the initialization - // logic in two steps. The pre-decorator initialization code runs, stores - // the initial value, and then we retrieve it here and apply the - // initializers added by decorators. We should unify these two steps. - if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) { - // [stack] ARRAY - return false; - } + // TODO: (See Bug 1817993) At the moment, we're applying the + // initialization logic in two steps. The pre-decorator initialization + // code runs, stores the initial value, and then we retrieve it here and + // apply the initializers added by decorators. We should unify these two + // steps. + if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_initializers_())) { + // [stack] ARRAY + return false; + } - if (!emit1(JSOp::Dup)) { - // [stack] ARRAY ARRAY - return false; - } + if (!emit1(JSOp::Dup)) { + // [stack] ARRAY ARRAY + return false; + } - if (!emitAtomOp(JSOp::GetProp, - TaggedParserAtomIndex::WellKnown::length())) { - // [stack] ARRAY LENGTH - return false; - } + if (!emitAtomOp(JSOp::GetProp, + TaggedParserAtomIndex::WellKnown::length())) { + // [stack] ARRAY LENGTH + return false; + } - if (!emitNumberOp(static_cast<double>(numInitializers))) { - // [stack] ARRAY LENGTH INDEX - return false; - } + if (!emitNumberOp(static_cast<double>(numInitializers))) { + // [stack] ARRAY LENGTH INDEX + return false; + } - InternalWhileEmitter wh(this); - // At this point, we have no context to determine offsets in the - // code for this while statement. Ideally, it would correspond to - // the field we're initializing. - if (!wh.emitCond()) { - // [stack] ARRAY LENGTH INDEX - return false; - } + InternalWhileEmitter wh(this); + // At this point, we have no context to determine offsets in the + // code for this while statement. Ideally, it would correspond to + // the field we're initializing. + if (!wh.emitCond()) { + // [stack] ARRAY LENGTH INDEX + return false; + } - if (!emit1(JSOp::Dup)) { - // [stack] ARRAY LENGTH INDEX INDEX - return false; - } + if (!emit1(JSOp::Dup)) { + // [stack] ARRAY LENGTH INDEX INDEX + return false; + } - if (!emitDupAt(2)) { - // [stack] ARRAY LENGTH INDEX INDEX LENGTH - return false; - } + if (!emitDupAt(2)) { + // [stack] ARRAY LENGTH INDEX INDEX LENGTH + return false; + } - if (!emit1(JSOp::Lt)) { - // [stack] ARRAY LENGTH INDEX BOOL - return false; - } + if (!emit1(JSOp::Lt)) { + // [stack] ARRAY LENGTH INDEX BOOL + return false; + } - if (!wh.emitBody()) { - // [stack] ARRAY LENGTH INDEX - return false; - } + if (!wh.emitBody()) { + // [stack] ARRAY LENGTH INDEX + return false; + } - if (!emitDupAt(2)) { - // [stack] ARRAY LENGTH INDEX ARRAY - return false; - } + if (!emitDupAt(2)) { + // [stack] ARRAY LENGTH INDEX ARRAY + return false; + } - if (!emitDupAt(1)) { - // [stack] ARRAY LENGTH INDEX ARRAY INDEX - return false; - } + if (!emitDupAt(1)) { + // [stack] ARRAY LENGTH INDEX ARRAY INDEX + return false; + } - // Retrieve initializers for this field - if (!emit1(JSOp::GetElem)) { - // [stack] ARRAY LENGTH INDEX INITIALIZERS - return false; - } + // Retrieve initializers for this field + if (!emit1(JSOp::GetElem)) { + // [stack] ARRAY LENGTH INDEX INITIALIZERS + return false; + } - // This is guaranteed to run after super(), so we don't need TDZ checks. - if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) { - // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS - return false; - } + // This is guaranteed to run after super(), so we don't need TDZ checks. + if (!emitGetName(TaggedParserAtomIndex::WellKnown::dot_this_())) { + // [stack] ARRAY LENGTH INDEX INITIALIZERS THIS + return false; + } - if (!emit1(JSOp::Swap)) { - // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS - return false; - } + if (!emit1(JSOp::Swap)) { + // [stack] ARRAY LENGTH INDEX THIS INITIALIZERS + return false; + } - DecoratorEmitter de(this); - if (!de.emitInitializeFieldOrAccessor()) { - // [stack] ARRAY LENGTH INDEX - return false; - } + DecoratorEmitter de(this); + if (!de.emitInitializeFieldOrAccessor()) { + // [stack] ARRAY LENGTH INDEX + return false; + } - if (!emit1(JSOp::Inc)) { - // [stack] ARRAY LENGTH INDEX - return false; - } + if (!emit1(JSOp::Inc)) { + // [stack] ARRAY LENGTH INDEX + return false; + } - if (!wh.emitEnd()) { - // [stack] ARRAY LENGTH INDEX - return false; - } + if (!wh.emitEnd()) { + // [stack] ARRAY LENGTH INDEX + return false; + } - if (!emitPopN(3)) { - // [stack] - return false; - } - // 5. Return unused. + if (!emitPopN(3)) { + // [stack] + return false; + } + // 5. Return unused. - if (!de.emitCallExtraInitializers(TaggedParserAtomIndex::WellKnown:: - dot_instanceExtraInitializers_())) { - return false; + if (!de.emitCallExtraInitializers(TaggedParserAtomIndex::WellKnown:: + dot_instanceExtraInitializers_())) { + return false; + } } #endif } @@ -12502,6 +12535,32 @@ bool BytecodeEmitter::emitTree( break; } + case ParseNodeKind::ArgumentsLength: { + if (sc->isFunctionBox() && + sc->asFunctionBox()->isEligibleForArgumentsLength() && + !sc->asFunctionBox()->needsArgsObj()) { + if (!emit1(JSOp::ArgumentsLength)) { + return false; + } + } else { + PropOpEmitter poe(this, PropOpEmitter::Kind::Get, + PropOpEmitter::ObjKind::Other); + if (!poe.prepareForObj()) { + return false; + } + + NameOpEmitter noe(this, TaggedParserAtomIndex::WellKnown::arguments(), + NameOpEmitter::Kind::Get); + if (!noe.emitGet()) { + return false; + } + if (!poe.emitGet(TaggedParserAtomIndex::WellKnown::length())) { + return false; + } + } + break; + } + case ParseNodeKind::ElemExpr: { PropertyByValue* elem = &pn->as<PropertyByValue>(); bool isSuper = elem->isSuper(); |