summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/BytecodeEmitter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/BytecodeEmitter.cpp')
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp255
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();