Issue #1658 - Part 2: Implement bytecode for optional chaining

Partially based on:
Bug 1566143 - Implement the Optional Chaining operator (?.) proposal
Bug 1650340 - Fix deleteElementInOptionalChain
Bug 1644839 - Fix return value of emitOptionalChain on failure
This commit is contained in:
FranklinDM 2022-04-26 01:16:59 +08:00 • committed by roytam1
commit d58db931d5
4 changed files with 1114 additions and 99 deletions

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,8 @@
#include "frontend/SourceNotes.h"
#include "vm/Interpreter.h"
class OptionalEmitter;
namespace js {
namespace frontend {
@ -456,6 +458,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitTree(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue,
EmitLineNumberNote emitLineNote = EMIT_LINENOTE);
// Emit code for the optional tree rooted at pn.
MOZ_MUST_USE bool emitOptionalTree(ParseNode* pn, OptionalEmitter& oe);
// Emit code for the tree rooted at pn with its own TDZ cache.
MOZ_MUST_USE bool emitTreeInBranch(ParseNode* pn,
ValueUsage valueUsage = ValueUsage::WantValue);
@ -731,6 +736,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitAsyncIterator();
// XXX currently used only by OptionalEmitter, research still required
// to identify when this was introduced in m-c.
MOZ_MUST_USE bool emitPushNotUndefinedOrNull();
// Pops iterator from the top of the stack. Pushes the result of |.next()|
// onto the stack.
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
@ -776,6 +785,29 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitDeleteElement(ParseNode* pn);
MOZ_MUST_USE bool emitDeleteExpression(ParseNode* pn);
// Optional methods which emit Optional Jump Target
MOZ_MUST_USE bool emitOptionalChain(ParseNode* optionalChain);
MOZ_MUST_USE bool emitCalleeAndThisForOptionalChain(ParseNode* optionalChain,
ParseNode* callNode,
bool isCall);
MOZ_MUST_USE bool emitDeleteOptionalChain(ParseNode* deleteNode);
// Optional methods which emit a shortCircuit jump. They need to be called by
// a method which emits an Optional Jump Target, see below.
MOZ_MUST_USE bool emitOptionalDotExpression(PropertyAccessBase* prop,
OptionalEmitter& oe,
ParseNode* calleeNode,
bool isCall);
MOZ_MUST_USE bool emitOptionalElemExpression(PropertyByValueBase* elem,
OptionalEmitter& oe,
ParseNode* calleeNode,
bool isCall);
MOZ_MUST_USE bool emitOptionalCall(ParseNode* callNode, OptionalEmitter& oe);
MOZ_MUST_USE bool emitDeletePropertyInOptChain(PropertyAccessBase* propExpr,
OptionalEmitter& oe);
MOZ_MUST_USE bool emitDeleteElementInOptChain(PropertyByValueBase* elemExpr,
OptionalEmitter& oe);
// |op| must be JSOP_TYPEOF or JSOP_TYPEOFEXPR.
MOZ_MUST_USE bool emitTypeof(ParseNode* node, JSOp op);
@ -794,7 +826,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result);
MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn,
ValueUsage valueUsage = ValueUsage::WantValue);
MOZ_MUST_USE bool emitCalleeAndThis(ParseNode* callNode,
ParseNode* calleeNode,
bool isCall);
MOZ_MUST_USE bool emitOptionalCalleeAndThis(ParseNode* callNode,
ParseNode* calleeNode,
bool isCall,
OptionalEmitter& oe);
MOZ_MUST_USE bool emitCallOrNewThis(ParseNode* callNode,
bool isCall);
MOZ_MUST_USE bool emitCallOrNewArgumentsAndEnd(ParseNode* callNode,
ParseNode* calleeNode,
bool isCall,
ValueUsage valueUsage);
MOZ_MUST_USE bool emitSelfHostedCallFunction(ParseNode* pn);
MOZ_MUST_USE bool emitSelfHostedResumeGenerator(ParseNode* pn);
MOZ_MUST_USE bool emitSelfHostedForceInterpreter(ParseNode* pn);

View file

@ -369,6 +369,10 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_DOT:
case PNK_ELEM:
case PNK_CALL:
case PNK_OPTCHAIN:
case PNK_OPTDOT:
case PNK_OPTELEM:
case PNK_OPTCALL:
case PNK_NAME:
case PNK_TEMPLATE_STRING:
case PNK_TEMPLATE_STRING_LIST:
@ -1529,7 +1533,9 @@ static bool
FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
bool inGenexpLambda)
{
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_SUPERCALL) ||
MOZ_ASSERT(node->isKind(PNK_CALL) ||
node->isKind(PNK_OPTCALL) ||
node->isKind(PNK_SUPERCALL) ||
node->isKind(PNK_TAGGED_TEMPLATE));
MOZ_ASSERT(node->isArity(PN_LIST));
@ -1826,6 +1832,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return FoldAdd(cx, pnp, parser, inGenexpLambda);
case PNK_CALL:
case PNK_OPTCALL:
case PNK_SUPERCALL:
case PNK_TAGGED_TEMPLATE:
return FoldCall(cx, pn, parser, inGenexpLambda);

View file

@ -699,6 +699,30 @@ IsEqualityOp(JSOp op)
return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
}
inline bool
IsSpreadOp(JSOp op)
{
return JOF_OPTYPE(op) == JOF_BYTE;
}
inline bool
IsNewOp(JSOp op)
{
return op == JSOP_NEW ||
op == JSOP_SPREADNEW ||
op == JSOP_SUPERCALL ||
op == JSOP_SPREADSUPERCALL;
}
inline bool
IsEvalOp(JSOp op)
{
return op == JSOP_EVAL ||
op == JSOP_STRICTEVAL ||
op == JSOP_SPREADEVAL ||
op == JSOP_STRICTSPREADEVAL;
}
inline bool
IsCheckStrictOp(JSOp op)
{