summaryrefslogtreecommitdiff
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.cpp209
1 files changed, 81 insertions, 128 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 4004273416..82e248182b 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -9396,19 +9396,9 @@ BytecodeEmitter::emitDeleteOptionalChain(ParseNode* deleteNode)
ParseNode* kid = deleteNode->pn_kid;
switch (kid->getKind()) {
- case PNK_ELEM: {
- PropertyByValue* elemExpr = &kid->as<PropertyByValue>();
- if (!emitDeleteElementInOptChain(elemExpr, oe)) {
- // [stack] # If shortcircuit
- // [stack] UNDEFINED-OR-NULL
- // [stack] # otherwise
- // [stack] TRUE
- return false;
- }
- break;
- }
+ case PNK_ELEM:
case PNK_OPTELEM: {
- OptionalPropertyByValue* elemExpr = &kid->as<OptionalPropertyByValue>();
+ PropertyByValueBase* elemExpr = &kid->as<PropertyByValueBase>();
if (!emitDeleteElementInOptChain(elemExpr, oe)) {
// [stack] # If shortcircuit
// [stack] UNDEFINED-OR-NULL
@@ -9418,19 +9408,9 @@ BytecodeEmitter::emitDeleteOptionalChain(ParseNode* deleteNode)
}
break;
}
- case PNK_DOT: {
- PropertyAccess* propExpr = &kid->as<PropertyAccess>();
- if (!emitDeletePropertyInOptChain(propExpr, oe)) {
- // [stack] # If shortcircuit
- // [stack] UNDEFINED-OR-NULL
- // [stack] # otherwise
- // [stack] TRUE
- return false;
- }
- break;
- }
+ case PNK_DOT:
case PNK_OPTDOT: {
- OptionalPropertyAccess* propExpr = &kid->as<OptionalPropertyAccess>();
+ PropertyAccessBase* propExpr = &kid->as<PropertyAccessBase>();
if (!emitDeletePropertyInOptChain(propExpr, oe)) {
// [stack] # If shortcircuit
// [stack] UNDEFINED-OR-NULL
@@ -9460,54 +9440,26 @@ BytecodeEmitter::emitDeletePropertyInOptChain(
PropertyAccessBase* propExpr,
OptionalEmitter& oe)
{
- if (propExpr->isSuper()) {
- // The expression |delete super.foo;| has to evaluate |super.foo|,
- // which could throw if |this| hasn't yet been set by a |super(...)|
- // call or the super-base is not an object, before throwing a
- // ReferenceError for attempting to delete a super-reference.
- ParseNode* base = &propExpr->expression();
- if (!emitGetThisForSuperBase(base)) {
- // [stack] THIS
- return false;
- }
- } else {
- if (!emitOptionalTree(&propExpr->expression(), oe)) {
+ MOZ_ASSERT_IF(propExpr->is<PropertyAccess>(),
+ !propExpr->as<PropertyAccess>().isSuper());
+
+ if (!emitOptionalTree(&propExpr->expression(), oe)) {
+ // [stack] OBJ
+ return false;
+ }
+ if (propExpr->isKind(PNK_OPTDOT)) {
+ if (!oe.emitJumpShortCircuit()) {
+ // [stack] # if Jump
+ // [stack] UNDEFINED-OR-NULL
+ // [stack] # otherwise
// [stack] OBJ
return false;
}
- if (propExpr->isKind(PNK_OPTDOT)) {
- if (!oe.emitJumpShortCircuit()) {
- // [stack] # if Jump
- // [stack] UNDEFINED-OR-NULL
- // [stack] # otherwise
- // [stack] OBJ
- return false;
- }
- }
}
- if (propExpr->isSuper()) {
- // Still have to calculate the base, even though we are are going
- // to throw unconditionally, as calculating the base could also
- // throw.
- if (!emit1(JSOP_SUPERBASE)) {
- return false;
- }
-
- if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER)) {
- return false;
- }
-
- // Another wrinkle: Balance the stack from the emitter's point of view.
- // Execution will not reach here, as the last bytecode threw.
- if (!emit1(JSOP_POP)) {
- return false;
- }
- } else {
- JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
- if (!emitAtomOp(propExpr, delOp)) {
- return false;
- }
+ JSOp delOp = sc->strict() ? JSOP_STRICTDELPROP : JSOP_DELPROP;
+ if (!emitAtomOp(propExpr, delOp)) {
+ return false;
}
return true;
@@ -9518,6 +9470,9 @@ BytecodeEmitter::emitDeleteElementInOptChain(
PropertyByValueBase* elemExpr,
OptionalEmitter& oe)
{
+ MOZ_ASSERT_IF(elemExpr->is<PropertyByValue>(),
+ !elemExpr->as<PropertyByValue>().isSuper());
+
if (!emitOptionalTree(elemExpr->pn_left, oe)) {
// [stack] OBJ
return false;
@@ -9538,19 +9493,6 @@ BytecodeEmitter::emitDeleteElementInOptChain(
return false;
}
- if (elemExpr->isSuper()) {
- if (!emit1(JSOP_SUPERBASE)) {
- return false;
- }
- if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_CANT_DELETE_SUPER)) {
- return false;
- }
-
- // Another wrinkle: Balance the stack from the emitter's point of view.
- // Execution will not reach here, as the last bytecode threw.
- return emit1(JSOP_POP);
- }
-
JSOp delOp = sc->strict() ? JSOP_STRICTDELELEM : JSOP_DELELEM;
return emitElemOpBase(delOp);
}
@@ -9858,18 +9800,11 @@ BytecodeEmitter::emitOptionalCalleeAndThis(
isCall = false;
break;
}
- case PNK_SUPERBASE: {
- MOZ_ASSERT(callNode->isKind(PNK_SUPERCALL));
- MOZ_ASSERT(parser->handler.isSuperBase(calleeNode));
- if (!emit1(JSOP_SUPERFUN)) {
- return false;
- }
- break;
- }
case PNK_OPTCHAIN: {
return emitCalleeAndThisForOptionalChain(calleeNode, callNode, isCall);
}
default: {
+ MOZ_RELEASE_ASSERT(calleeNode->getKind() != PNK_SUPERBASE);
if (!emitOptionalTree(calleeNode, oe)) {
return false;
}
@@ -9899,10 +9834,10 @@ BytecodeEmitter::emitOptionalCalleeAndThis(
bool
BytecodeEmitter::emitOptionalCall(
ParseNode* callNode,
- OptionalEmitter& oe)
+ OptionalEmitter& oe,
+ ValueUsage valueUsage)
{
bool isCall = true;
- ValueUsage valueUsage = ValueUsage::WantValue;
ParseNode* calleeNode = callNode->pn_head;
if (!emitOptionalCalleeAndThis(callNode, calleeNode, isCall, oe)) {
@@ -11509,7 +11444,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break;
case PNK_OPTCHAIN:
- if (!emitOptionalChain(pn)) {
+ if (!emitOptionalChain(pn, valueUsage)) {
return false;
}
break;
@@ -11713,7 +11648,8 @@ BytecodeEmitter::emitTreeInBranch(ParseNode* pn,
bool
BytecodeEmitter::emitOptionalTree(
ParseNode* pn,
- OptionalEmitter& oe)
+ OptionalEmitter& oe,
+ ValueUsage valueUsage /* = ValueUsage::WantValue */)
{
JS_CHECK_RECURSION(cx, return false);
@@ -11749,7 +11685,7 @@ BytecodeEmitter::emitOptionalTree(
}
case PNK_CALL:
case PNK_OPTCALL: {
- if (!emitOptionalCall(pn, oe)) {
+ if (!emitOptionalCall(pn, oe, valueUsage)) {
return false;
}
break;
@@ -11759,28 +11695,38 @@ BytecodeEmitter::emitOptionalTree(
// For example, a taggedTemplateExpr node might occur if we have
// `test`?.b, with `test` as the taggedTemplateExpr ParseNode.
default: {
- MOZ_ASSERT(
- (kind == PNK_ARRAY ||
- kind == PNK_OBJECT ||
- kind == PNK_TRUE ||
- kind == PNK_FALSE ||
- kind == PNK_STRING ||
- kind == PNK_NUMBER ||
- kind == PNK_RAW_UNDEFINED ||
- kind == PNK_NULL ||
- kind == PNK_NAME ||
- kind == PNK_FUNCTION ||
- kind == PNK_THIS ||
- kind == PNK_TAGGED_TEMPLATE ||
- kind == PNK_TEMPLATE_STRING ||
- kind == PNK_AWAIT ||
- kind == PNK_REGEXP ||
- kind == PNK_CLASS ||
- kind == PNK_COMMA ||
- kind == PNK_NEW ||
- kind == PNK_SETTHIS ||
- kind == PNK_NEWTARGET),
- "Unknown ParseNodeKind for OptionalChain");
+#ifdef DEBUG
+ // https://tc39.es/ecma262/#sec-primary-expression
+ bool isPrimaryExpression =
+ kind == PNK_THIS ||
+ kind == PNK_NAME ||
+ kind == PNK_NULL ||
+ kind == PNK_TRUE ||
+ kind == PNK_FALSE ||
+ kind == PNK_NUMBER ||
+ kind == PNK_STRING ||
+ kind == PNK_ARRAY ||
+ kind == PNK_OBJECT ||
+ kind == PNK_FUNCTION ||
+ kind == PNK_CLASS ||
+ kind == PNK_REGEXP ||
+ kind == PNK_TEMPLATE_STRING ||
+ kind == PNK_RAW_UNDEFINED ||
+ pn->isInParens();
+
+ // https://tc39.es/ecma262/#sec-left-hand-side-expressions
+ bool isMemberExpression = isPrimaryExpression ||
+ kind == PNK_TAGGED_TEMPLATE ||
+ kind == PNK_NEW ||
+ kind == PNK_NEWTARGET;
+ //kind == ParseNodeKind::ImportMetaExpr;
+
+ bool isCallExpression = kind == PNK_SETTHIS;
+ //kind == ParseNodeKind::CallImportExpr;
+
+ MOZ_ASSERT(isMemberExpression || isCallExpression,
+ "Unknown ParseNodeKind for OptionalChain");
+#endif
return emitTree(pn);
}
}
@@ -11824,13 +11770,15 @@ BytecodeEmitter::emitCalleeAndThisForOptionalChain(
}
bool
-BytecodeEmitter::emitOptionalChain(ParseNode* optionalChain)
+BytecodeEmitter::emitOptionalChain(
+ ParseNode* optionalChain,
+ ValueUsage valueUsage)
{
ParseNode* expression = optionalChain->pn_kid;
OptionalEmitter oe(this, stackDepth);
- if (!emitOptionalTree(expression, oe)) {
+ if (!emitOptionalTree(expression, oe, valueUsage)) {
// [stack] VAL
return false;
}
@@ -11853,12 +11801,13 @@ BytecodeEmitter::emitOptionalDotExpression(
ParseNode* calleeNode,
bool isCall)
{
- bool isSuper = prop->isSuper();
+ bool isSuper = prop->is<PropertyAccess>() &&
+ prop->as<PropertyAccess>().isSuper();
ParseNode* base = &prop->expression();
if (isSuper) {
if (!emitGetThisForSuperBase(base)) {
- // [stack] THIS
+ // [stack] OBJ
return false;
}
} else {
@@ -11869,6 +11818,7 @@ BytecodeEmitter::emitOptionalDotExpression(
}
if (prop->isKind(PNK_OPTDOT)) {
+ MOZ_ASSERT(!isSuper);
if (!oe.emitJumpShortCircuit()) {
// [stack] # if Jump
// [stack] UNDEFINED-OR-NULL
@@ -11915,20 +11865,23 @@ BytecodeEmitter::emitOptionalElemExpression(
ParseNode* calleeNode,
bool isCall)
{
- if (elem->isSuper()) {
- if (!emitSuperElemOp(calleeNode, JSOP_GETELEM_SUPER, isCall)) {
+ bool isSuper = elem->is<PropertyByValue>() &&
+ elem->as<PropertyByValue>().isSuper();
+
+ if (isSuper) {
+ if (!emitGetThisForSuperBase(calleeNode)) {
+ // [stack] OBJ
+ return false;
+ }
+ } else {
+ if (!emitOptionalTree(calleeNode->pn_left, oe)) {
+ // [stack] OBJ
return false;
}
-
- return true;
- }
-
- if (!emitOptionalTree(calleeNode->pn_left, oe)) {
- // [stack] OBJ
- return false;
}
if (elem->isKind(PNK_OPTELEM)) {
+ MOZ_ASSERT(!isSuper);
if (!oe.emitJumpShortCircuit()) {
// [stack] # if Jump
// [stack] UNDEFINED-OR-NULL