diff options
-rw-r--r-- | js/src/frontend/BytecodeEmitter.cpp | 55 | ||||
-rw-r--r-- | js/src/frontend/BytecodeEmitter.h | 5 |
2 files changed, 39 insertions, 21 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index d2b47089a0..f192220e30 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -73,6 +73,20 @@ ParseNodeRequiresSpecialLineNumberNotes(ParseNode* pn) return pn->getKind() == PNK_WHILE || pn->getKind() == PNK_FOR; } +uint32_t +GetCallArgsAndCount(ParseNode* callNode, ParseNode** argumentNode) +{ + // XXX This helper function exists to make ports less error-prone. + // The current parse tree splits the information between callNode and callee. + // A later refactor has a ListNode instead, with slightly different storage. + // (See also the "what is stored where" table in ParseNode.h) + ParseNode* calleeNode = callNode->pn_head; + if (argumentNode && calleeNode) { + *argumentNode = calleeNode->pn_next; + } + return callNode->pn_count - 1; +} + class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::NestableControl> { StatementKind kind_; @@ -9361,13 +9375,13 @@ BytecodeEmitter::emitOptionalCall( ParseNode* calleeNode = callNode->pn_head; bool isCall = true; bool isSpread = IsSpreadOp(callNode->getOp()); - ListNode* argsList = &callNode->pn_right->as<ListNode>(); + ParseNode* firstArg = nullptr; + uint32_t argc = GetCallArgsAndCount(callNode, &firstArg); JSOp op = callNode->getOp(); - uint32_t argc = argsList->pn_count; CallOrNewEmitter cone(this, op, isSpread && (argc == 1) && - isRestParameter(argsList->pn_head->as<UnaryNode>().pn_kid) + isRestParameter(firstArg->pn_kid) ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest : CallOrNewEmitter::ArgumentsKind::Other, valueUsage); @@ -9384,12 +9398,12 @@ BytecodeEmitter::emitOptionalCall( } } - if (!emitArguments(argsList, /* isCall = */ true, isSpread, cone)) { + if (!emitArguments(firstArg, argc, /* isCall = */ true, isSpread, cone)) { // [stack] CALLEE THIS ARGS... return false; } - ParseNode* coordNode = getCoordNode(callNode, calleeNode, argsList); + ParseNode* coordNode = getCoordNode(callNode, calleeNode, firstArg); if (!cone.emitEnd(argc, Some(coordNode->pn_pos.begin))) { // [stack] RVAL return false; @@ -9400,14 +9414,17 @@ BytecodeEmitter::emitOptionalCall( ParseNode* BytecodeEmitter::getCoordNode(ParseNode* pn, ParseNode* calleeNode, - ParseNode* argsList) { + ParseNode* firstArg) { ParseNode* coordNode = pn; if (pn->isOp(JSOP_CALL) || pn->isOp(JSOP_SPREADCALL) || pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY)) { // Default to using the location of the `(` itself. // obj[expr]() // expression // ^ // column coord - coordNode = argsList; + if (firstArg) { + // XXX In our version, firstArg points to the first argument and may be null if there are none + coordNode = firstArg; + } switch (calleeNode->getKind()) { case PNK_DOT: @@ -9435,34 +9452,34 @@ ParseNode* BytecodeEmitter::getCoordNode(ParseNode* pn, } bool -BytecodeEmitter::emitArguments(ListNode* argsList, bool isCall, bool isSpread, +BytecodeEmitter::emitArguments(ParseNode* firstArgNode, uint32_t argc, bool isCall, bool isSpread, CallOrNewEmitter& cone) { - uint32_t argc = argsList->pn_count; if (argc >= ARGC_LIMIT) { - reportError(argsList, isCall ? JSMSG_TOO_MANY_FUN_ARGS : JSMSG_TOO_MANY_CON_ARGS); + parser->tokenStream.reportError(isCall + ? JSMSG_TOO_MANY_FUN_ARGS + : JSMSG_TOO_MANY_CON_ARGS); return false; } if (!isSpread) { if (!cone.prepareForNonSpreadArguments()) { // CALLEE THIS return false; } - for (ParseNode* arg = argsList->pn_head; arg; arg = arg->pn_next) { + for (ParseNode* arg = firstArgNode; arg; arg = arg->pn_next) { if (!emitTree(arg)) { return false; } } } else { if (cone.wantSpreadOperand()) { - UnaryNode* spreadNode = &argsList->pn_head->as<UnaryNode>(); - if (!emitTree(spreadNode->pn_kid)) { // CALLEE THIS ARG0 + if (!emitTree(firstArgNode->pn_kid)) { // CALLEE THIS ARG0 return false; } } if (!cone.emitSpreadArgumentsTest()) { // CALLEE THIS return false; } - if (!emitArray(argsList->pn_head, argc, JSOP_NEWARRAY)) { // CALLEE THIS ARR + if (!emitArray(firstArgNode, argc, JSOP_SPREADCALLARRAY)) { // CALLEE THIS ARR return false; } } @@ -9493,7 +9510,8 @@ BytecodeEmitter::emitCallOrNew( ParseNode* calleeNode = callNode->pn_head; bool isCall = callNode->isKind(PNK_CALL) || callNode->isKind(PNK_TAGGED_TEMPLATE); bool isSpread = IsSpreadOp(callNode->getOp()); - ListNode* argsList = &callNode->pn_right->as<ListNode>(); + ParseNode* firstArg = nullptr; + uint32_t argc = GetCallArgsAndCount(callNode, &firstArg); if (calleeNode->isKind(PNK_NAME) && emitterMode == BytecodeEmitter::SelfHosting && @@ -9518,21 +9536,20 @@ BytecodeEmitter::emitCallOrNew( } JSOp op = callNode->getOp(); - uint32_t argc = argsList->pn_count; CallOrNewEmitter cone(this, op, isSpread && (argc == 1) && - isRestParameter(argsList->pn_head->as<UnaryNode>().pn_kid) + isRestParameter(firstArg->pn_kid) ? CallOrNewEmitter::ArgumentsKind::SingleSpreadRest : CallOrNewEmitter::ArgumentsKind::Other, valueUsage); if (!emitCalleeAndThis(callNode, calleeNode, cone)) { // CALLEE THIS return false; } - if (!emitArguments(argsList, isCall, isSpread, cone)) { + if (!emitArguments(firstArg, argc, isCall, isSpread, cone)) { return false; // CALLEE THIS ARGS... } - ParseNode* coordNode = getCoordNode(callNode, calleeNode, argsList); + ParseNode* coordNode = getCoordNode(callNode, calleeNode, firstArg); if (!cone.emitEnd(argc, Some(coordNode->pn_pos.begin))) { return false; // RVAL diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index 025d6035fe..956ade1545 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -753,8 +753,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted); MOZ_MUST_USE ParseNode* getCoordNode(ParseNode* callNode, ParseNode* calleeNode, - ParseNode* argsList); - MOZ_MUST_USE bool emitArguments(ListNode* argsList, bool isCall, bool isSpread, + ParseNode* firstArgNode); + MOZ_MUST_USE bool emitArguments(ParseNode* firstArgNode, uint32_t argc, + bool isCall, bool isSpread, CallOrNewEmitter& cone); MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); |