Backed out changeset e01d0f7a3c6f (bug 1135708) for spidermonkey errors CLOSED TREE

This commit is contained in:
Wes Kocher 2015-07-27 15:22:40 -07:00
parent b9d1502b8e
commit 845f981fa5
19 changed files with 63 additions and 337 deletions

View File

@ -47,7 +47,7 @@ enum AssignmentOperator {
/* assign */ /* assign */
AOP_ASSIGN = 0, AOP_ASSIGN = 0,
/* operator-assign */ /* operator-assign */
AOP_PLUS, AOP_MINUS, AOP_STAR, AOP_DIV, AOP_MOD, AOP_POW, AOP_PLUS, AOP_MINUS, AOP_STAR, AOP_DIV, AOP_MOD,
/* shift-assign */ /* shift-assign */
AOP_LSH, AOP_RSH, AOP_URSH, AOP_LSH, AOP_RSH, AOP_URSH,
/* binary */ /* binary */
@ -66,7 +66,7 @@ enum BinaryOperator {
/* shift */ /* shift */
BINOP_LSH, BINOP_RSH, BINOP_URSH, BINOP_LSH, BINOP_RSH, BINOP_URSH,
/* arithmetic */ /* arithmetic */
BINOP_ADD, BINOP_SUB, BINOP_STAR, BINOP_DIV, BINOP_MOD, BINOP_POW, BINOP_ADD, BINOP_SUB, BINOP_STAR, BINOP_DIV, BINOP_MOD,
/* binary */ /* binary */
BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND, BINOP_BITOR, BINOP_BITXOR, BINOP_BITAND,
/* misc */ /* misc */
@ -113,7 +113,6 @@ static const char* const aopNames[] = {
"*=", /* AOP_STAR */ "*=", /* AOP_STAR */
"/=", /* AOP_DIV */ "/=", /* AOP_DIV */
"%=", /* AOP_MOD */ "%=", /* AOP_MOD */
"**=", /* AOP_POW */
"<<=", /* AOP_LSH */ "<<=", /* AOP_LSH */
">>=", /* AOP_RSH */ ">>=", /* AOP_RSH */
">>>=", /* AOP_URSH */ ">>>=", /* AOP_URSH */
@ -139,7 +138,6 @@ static const char* const binopNames[] = {
"*", /* BINOP_STAR */ "*", /* BINOP_STAR */
"/", /* BINOP_DIV */ "/", /* BINOP_DIV */
"%", /* BINOP_MOD */ "%", /* BINOP_MOD */
"**", /* BINOP_POW */
"|", /* BINOP_BITOR */ "|", /* BINOP_BITOR */
"^", /* BINOP_BITXOR */ "^", /* BINOP_BITXOR */
"&", /* BINOP_BITAND */ "&", /* BINOP_BITAND */
@ -1860,7 +1858,6 @@ class ASTSerializer
bool statements(ParseNode* pn, NodeVector& elts); bool statements(ParseNode* pn, NodeVector& elts);
bool expressions(ParseNode* pn, NodeVector& elts); bool expressions(ParseNode* pn, NodeVector& elts);
bool leftAssociate(ParseNode* pn, MutableHandleValue dst); bool leftAssociate(ParseNode* pn, MutableHandleValue dst);
bool rightAssociate(ParseNode* pn, MutableHandleValue dst);
bool functionArgs(ParseNode* pn, ParseNode* pnargs, ParseNode* pnbody, bool functionArgs(ParseNode* pn, ParseNode* pnargs, ParseNode* pnbody,
NodeVector& args, NodeVector& defaults, MutableHandleValue rest); NodeVector& args, NodeVector& defaults, MutableHandleValue rest);
@ -1977,8 +1974,6 @@ ASTSerializer::aop(JSOp op)
return AOP_DIV; return AOP_DIV;
case JSOP_MOD: case JSOP_MOD:
return AOP_MOD; return AOP_MOD;
case JSOP_POW:
return AOP_POW;
case JSOP_LSH: case JSOP_LSH:
return AOP_LSH; return AOP_LSH;
case JSOP_RSH: case JSOP_RSH:
@ -2057,8 +2052,6 @@ ASTSerializer::binop(ParseNodeKind kind, JSOp op)
return BINOP_DIV; return BINOP_DIV;
case PNK_MOD: case PNK_MOD:
return BINOP_MOD; return BINOP_MOD;
case PNK_POW:
return BINOP_POW;
case PNK_BITOR: case PNK_BITOR:
return BINOP_BITOR; return BINOP_BITOR;
case PNK_BITXOR: case PNK_BITXOR:
@ -2793,49 +2786,6 @@ ASTSerializer::leftAssociate(ParseNode* pn, MutableHandleValue dst)
return true; return true;
} }
bool
ASTSerializer::rightAssociate(ParseNode* pn, MutableHandleValue dst)
{
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count >= 1);
// First, we need to reverse the list, so that we can traverse it in the right order.
// It's OK to destructively reverse the list, because there are no other consumers.
ParseNode* head = pn->pn_head;
ParseNode* prev = nullptr;
ParseNode* current = head;
ParseNode* next;
while (current != nullptr) {
next = current->pn_next;
current->pn_next = prev;
prev = current;
current = next;
}
head = prev;
RootedValue right(cx);
if (!expression(head, &right))
return false;
for (ParseNode* next = head->pn_next; next; next = next->pn_next) {
RootedValue left(cx);
if (!expression(next, &left))
return false;
TokenPos subpos(pn->pn_pos.begin, next->pn_pos.end);
BinaryOperator op = binop(pn->getKind(), pn->getOp());
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
if (!builder.binaryExpression(op, left, right, &subpos, &right))
return false;
}
dst.set(right);
return true;
}
bool bool
ASTSerializer::comprehensionBlock(ParseNode* pn, MutableHandleValue dst) ASTSerializer::comprehensionBlock(ParseNode* pn, MutableHandleValue dst)
{ {
@ -3024,7 +2974,6 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_MULASSIGN: case PNK_MULASSIGN:
case PNK_DIVASSIGN: case PNK_DIVASSIGN:
case PNK_MODASSIGN: case PNK_MODASSIGN:
case PNK_POWASSIGN:
{ {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos)); MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos)); MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
@ -3061,9 +3010,6 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_INSTANCEOF: case PNK_INSTANCEOF:
return leftAssociate(pn, dst); return leftAssociate(pn, dst);
case PNK_POW:
return rightAssociate(pn, dst);
case PNK_DELETENAME: case PNK_DELETENAME:
case PNK_DELETEPROP: case PNK_DELETEPROP:
case PNK_DELETESUPERPROP: case PNK_DELETESUPERPROP:

View File

@ -2039,7 +2039,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_MULASSIGN: case PNK_MULASSIGN:
case PNK_DIVASSIGN: case PNK_DIVASSIGN:
case PNK_MODASSIGN: case PNK_MODASSIGN:
case PNK_POWASSIGN:
MOZ_ASSERT(pn->isArity(PN_BINARY)); MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true; *answer = true;
return true; return true;
@ -2092,7 +2091,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_STAR: case PNK_STAR:
case PNK_DIV: case PNK_DIV:
case PNK_MOD: case PNK_MOD:
case PNK_POW:
MOZ_ASSERT(pn->isArity(PN_LIST)); MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count >= 2); MOZ_ASSERT(pn->pn_count >= 2);
*answer = true; *answer = true;
@ -7732,7 +7730,6 @@ BytecodeEmitter::emitTree(ParseNode* pn)
case PNK_MULASSIGN: case PNK_MULASSIGN:
case PNK_DIVASSIGN: case PNK_DIVASSIGN:
case PNK_MODASSIGN: case PNK_MODASSIGN:
case PNK_POWASSIGN:
if (!emitAssignment(pn->pn_left, pn->getOp(), pn->pn_right)) if (!emitAssignment(pn->pn_left, pn->getOp(), pn->pn_right))
return false; return false;
break; break;
@ -7782,20 +7779,6 @@ BytecodeEmitter::emitTree(ParseNode* pn)
break; break;
} }
case PNK_POW: {
MOZ_ASSERT(pn->isArity(PN_LIST));
/* Right-associative operator chain. */
for (ParseNode* subexpr = pn->pn_head; subexpr; subexpr = subexpr->pn_next) {
if (!emitTree(subexpr))
return false;
}
for (int i = 0; i < pn->pn_count - 1; i++) {
if (!emit1(JSOP_POW))
return false;
}
break;
}
case PNK_TYPEOFNAME: case PNK_TYPEOFNAME:
ok = emitTypeof(pn, JSOP_TYPEOF); ok = emitTypeof(pn, JSOP_TYPEOF);
break; break;

View File

@ -363,7 +363,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_STAR: case PNK_STAR:
case PNK_DIV: case PNK_DIV:
case PNK_MOD: case PNK_MOD:
case PNK_POW:
case PNK_ASSIGN: case PNK_ASSIGN:
case PNK_ADDASSIGN: case PNK_ADDASSIGN:
case PNK_SUBASSIGN: case PNK_SUBASSIGN:
@ -376,7 +375,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_MULASSIGN: case PNK_MULASSIGN:
case PNK_DIVASSIGN: case PNK_DIVASSIGN:
case PNK_MODASSIGN: case PNK_MODASSIGN:
case PNK_POWASSIGN:
case PNK_COMMA: case PNK_COMMA:
case PNK_ARRAY: case PNK_ARRAY:
case PNK_OBJECT: case PNK_OBJECT:
@ -532,10 +530,6 @@ FoldBinaryNumeric(ExclusiveContext* cx, JSOp op, ParseNode* pn1, ParseNode* pn2,
} }
break; break;
case JSOP_POW:
d = ecmaPow(d, d2);
break;
default:; default:;
} }
@ -1404,7 +1398,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_URSH: case PNK_URSH:
case PNK_DIV: case PNK_DIV:
case PNK_MOD: case PNK_MOD:
case PNK_POW:
MOZ_ASSERT(pn->getArity() == PN_LIST); MOZ_ASSERT(pn->getArity() == PN_LIST);
MOZ_ASSERT(pn->pn_count >= 2); MOZ_ASSERT(pn->pn_count >= 2);
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) { for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
@ -1416,12 +1409,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
if (!pn2->isKind(PNK_NUMBER)) if (!pn2->isKind(PNK_NUMBER))
break; break;
} }
// No constant-folding for (2**3**5), because (**) is right-
// associative. We would have to reverse the list. It's not worth it.
if (pn->getKind() == PNK_POW && pn->pn_count > 2)
break;
if (!pn2) { if (!pn2) {
JSOp op = pn->getOp(); JSOp op = pn->getOp();

View File

@ -439,7 +439,6 @@ class NameResolver
case PNK_MULASSIGN: case PNK_MULASSIGN:
case PNK_DIVASSIGN: case PNK_DIVASSIGN:
case PNK_MODASSIGN: case PNK_MODASSIGN:
case PNK_POWASSIGN:
case PNK_ELEM: case PNK_ELEM:
case PNK_COLON: case PNK_COLON:
case PNK_CASE: case PNK_CASE:
@ -660,7 +659,6 @@ class NameResolver
case PNK_STAR: case PNK_STAR:
case PNK_DIV: case PNK_DIV:
case PNK_MOD: case PNK_MOD:
case PNK_POW:
case PNK_COMMA: case PNK_COMMA:
case PNK_NEW: case PNK_NEW:
case PNK_CALL: case PNK_CALL:

View File

@ -272,7 +272,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_MULASSIGN: case PNK_MULASSIGN:
case PNK_DIVASSIGN: case PNK_DIVASSIGN:
case PNK_MODASSIGN: case PNK_MODASSIGN:
case PNK_POWASSIGN:
// ...and a few others. // ...and a few others.
case PNK_ELEM: case PNK_ELEM:
case PNK_IMPORT_SPEC: case PNK_IMPORT_SPEC:
@ -479,7 +478,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_STAR: case PNK_STAR:
case PNK_DIV: case PNK_DIV:
case PNK_MOD: case PNK_MOD:
case PNK_POW:
case PNK_COMMA: case PNK_COMMA:
case PNK_NEW: case PNK_NEW:
case PNK_CALL: case PNK_CALL:
@ -613,18 +611,7 @@ ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode* left, Pars
// processing such a tree, exactly implemented that way, would blow the // processing such a tree, exactly implemented that way, would blow the
// the stack. We use a list node that uses O(1) stack to represent // the stack. We use a list node that uses O(1) stack to represent
// such operations: (+ a b c). // such operations: (+ a b c).
// if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
// (**) is right-associative; per spec |a ** b ** c| parses as
// (** a (** b c)). But we treat this the same way, creating a list
// node: (** a b c). All consumers must understand that this must be
// processed with a right fold, whereas the list (+ a b c) must be
// processed with a left fold because (+) is left-associative.
//
if (left->isKind(kind) &&
left->isOp(op) &&
(js_CodeSpec[op].format & JOF_LEFTASSOC ||
(kind == PNK_POW && !left->pn_parens)))
{
ListNode* list = &left->as<ListNode>(); ListNode* list = &left->as<ListNode>();
list->append(right); list->append(right);

View File

@ -197,7 +197,6 @@ class UpvarCookie
F(STAR) \ F(STAR) \
F(DIV) \ F(DIV) \
F(MOD) \ F(MOD) \
F(POW) \
\ \
/* Assignment operators (= += -= etc.). */ \ /* Assignment operators (= += -= etc.). */ \
/* ParseNode::isAssignment assumes all these are consecutive. */ \ /* ParseNode::isAssignment assumes all these are consecutive. */ \
@ -212,8 +211,7 @@ class UpvarCookie
F(URSHASSIGN) \ F(URSHASSIGN) \
F(MULASSIGN) \ F(MULASSIGN) \
F(DIVASSIGN) \ F(DIVASSIGN) \
F(MODASSIGN) \ F(MODASSIGN)
F(POWASSIGN)
/* /*
* Parsing builds a tree of nodes that directs code generation. This tree is * Parsing builds a tree of nodes that directs code generation. This tree is
@ -232,9 +230,9 @@ enum ParseNodeKind
#undef EMIT_ENUM #undef EMIT_ENUM
PNK_LIMIT, /* domain size */ PNK_LIMIT, /* domain size */
PNK_BINOP_FIRST = PNK_OR, PNK_BINOP_FIRST = PNK_OR,
PNK_BINOP_LAST = PNK_POW, PNK_BINOP_LAST = PNK_MOD,
PNK_ASSIGNMENT_START = PNK_ASSIGN, PNK_ASSIGNMENT_START = PNK_ASSIGN,
PNK_ASSIGNMENT_LAST = PNK_POWASSIGN PNK_ASSIGNMENT_LAST = PNK_MODASSIGN
}; };
inline bool inline bool
@ -371,34 +369,31 @@ IsDeleteKind(ParseNodeKind kind)
* PNK_URSHASSIGN, * PNK_URSHASSIGN,
* PNK_MULASSIGN, * PNK_MULASSIGN,
* PNK_DIVASSIGN, * PNK_DIVASSIGN,
* PNK_MODASSIGN, * PNK_MODASSIGN
* PNK_POWASSIGN
* PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr) * PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
* pn_kid1: cond, pn_kid2: then, pn_kid3: else * pn_kid1: cond, pn_kid2: then, pn_kid3: else
* PNK_OR, list pn_head; list of pn_count subexpressions * PNK_OR binary pn_left: first in || chain, pn_right: rest of chain
* PNK_AND, All of these operators are left-associative except (**). * PNK_AND binary pn_left: first in && chain, pn_right: rest of chain
* PNK_BITOR, * PNK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
* PNK_BITXOR, * PNK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr
* PNK_BITAND, * PNK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr
* PNK_EQ, *
* PNK_EQ, binary pn_left: left-assoc EQ expr, pn_right: REL expr
* PNK_NE, * PNK_NE,
* PNK_STRICTEQ, * PNK_STRICTEQ,
* PNK_STRICTNE, * PNK_STRICTNE
* PNK_LT, * PNK_LT, binary pn_left: left-assoc REL expr, pn_right: SH expr
* PNK_LE, * PNK_LE,
* PNK_GT, * PNK_GT,
* PNK_GE, * PNK_GE
* PNK_LSH, * PNK_LSH, binary pn_left: left-assoc SH expr, pn_right: ADD expr
* PNK_RSH, * PNK_RSH,
* PNK_URSH, * PNK_URSH
* PNK_ADD, * PNK_ADD, binary pn_left: left-assoc ADD expr, pn_right: MUL expr
* PNK_SUB, * PNK_SUB
* PNK_STAR, * PNK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr
* PNK_DIV, * PNK_DIV, pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
* PNK_MOD, * PNK_MOD
* PNK_POW (**) is right-associative, but forms a list
* nonetheless. Special hacks everywhere.
*
* PNK_POS, unary pn_kid: UNARY expr * PNK_POS, unary pn_kid: UNARY expr
* PNK_NEG * PNK_NEG
* PNK_VOID, unary pn_kid: UNARY expr * PNK_VOID, unary pn_kid: UNARY expr

View File

@ -6351,8 +6351,7 @@ static const JSOp ParseNodeKindToJSOp[] = {
JSOP_SUB, JSOP_SUB,
JSOP_MUL, JSOP_MUL,
JSOP_DIV, JSOP_DIV,
JSOP_MOD, JSOP_MOD
JSOP_POW
}; };
static inline JSOp static inline JSOp
@ -6393,11 +6392,10 @@ static const int PrecedenceTable[] = {
9, /* PNK_SUB */ 9, /* PNK_SUB */
10, /* PNK_STAR */ 10, /* PNK_STAR */
10, /* PNK_DIV */ 10, /* PNK_DIV */
10, /* PNK_MOD */ 10 /* PNK_MOD */
11 /* PNK_POW */
}; };
static const int PRECEDENCE_CLASSES = 11; static const int PRECEDENCE_CLASSES = 10;
static int static int
Precedence(ParseNodeKind pnk) { Precedence(ParseNodeKind pnk) {
@ -6417,8 +6415,8 @@ MOZ_ALWAYS_INLINE typename ParseHandler::Node
Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling, Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling,
InvokedPrediction invoked) InvokedPrediction invoked)
{ {
// Shift-reduce parser for the binary operator part of the JS expression // Shift-reduce parser for the left-associative binary operator part of
// syntax. // the JS syntax.
// Conceptually there's just one stack, a stack of pairs (lhs, op). // Conceptually there's just one stack, a stack of pairs (lhs, op).
// It's implemented using two separate arrays, though. // It's implemented using two separate arrays, though.
@ -6450,9 +6448,10 @@ Parser<ParseHandler>::orExpr1(InHandling inHandling, YieldHandling yieldHandling
// stack, reduce. This combines nodes on the stack until we form the // stack, reduce. This combines nodes on the stack until we form the
// actual lhs of pnk. // actual lhs of pnk.
// //
// The >= in this condition works because it is appendOrCreateList's // The >= in this condition works because all the operators in question
// job to decide if the operator in question is left- or // are left-associative; if any were not, the case where two operators
// right-associative, and build the corresponding tree. // have equal precedence would need to be handled specially, and the
// stack would need to be a Vector.
while (depth > 0 && Precedence(kindStack[depth - 1]) >= Precedence(pnk)) { while (depth > 0 && Precedence(kindStack[depth - 1]) >= Precedence(pnk)) {
depth--; depth--;
ParseNodeKind combiningPnk = kindStack[depth]; ParseNodeKind combiningPnk = kindStack[depth];
@ -6614,7 +6613,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
case TOK_MULASSIGN: kind = PNK_MULASSIGN; op = JSOP_MUL; break; case TOK_MULASSIGN: kind = PNK_MULASSIGN; op = JSOP_MUL; break;
case TOK_DIVASSIGN: kind = PNK_DIVASSIGN; op = JSOP_DIV; break; case TOK_DIVASSIGN: kind = PNK_DIVASSIGN; op = JSOP_DIV; break;
case TOK_MODASSIGN: kind = PNK_MODASSIGN; op = JSOP_MOD; break; case TOK_MODASSIGN: kind = PNK_MODASSIGN; op = JSOP_MOD; break;
case TOK_POWASSIGN: kind = PNK_POWASSIGN; op = JSOP_POW; break;
case TOK_ARROW: { case TOK_ARROW: {
// A line terminator between ArrowParameters and the => should trigger a SyntaxError. // A line terminator between ArrowParameters and the => should trigger a SyntaxError.

View File

@ -122,7 +122,7 @@
* range-testing. \ * range-testing. \
*/ \ */ \
/* \ /* \
* Binary operators tokens, TOK_OR thru TOK_POW. These must be in the same \ * Binary operators tokens, TOK_OR thru TOK_MOD. These must be in the same \
* order as F(OR) and friends in FOR_EACH_PARSE_NODE_KIND in ParseNode.h. \ * order as F(OR) and friends in FOR_EACH_PARSE_NODE_KIND in ParseNode.h. \
*/ \ */ \
macro(OR, "'||'") /* logical or */ \ macro(OR, "'||'") /* logical or */ \
@ -163,8 +163,7 @@
macro(MUL, "'*'") \ macro(MUL, "'*'") \
macro(DIV, "'/'") \ macro(DIV, "'/'") \
macro(MOD, "'%'") \ macro(MOD, "'%'") \
macro(POW, "'**'") \ range(BINOP_LAST, MOD) \
range(BINOP_LAST, POW) \
\ \
/* Unary operation tokens. */ \ /* Unary operation tokens. */ \
macro(TYPEOF, "keyword 'typeof'") \ macro(TYPEOF, "keyword 'typeof'") \
@ -188,8 +187,7 @@
macro(MULASSIGN, "'*='") \ macro(MULASSIGN, "'*='") \
macro(DIVASSIGN, "'/='") \ macro(DIVASSIGN, "'/='") \
macro(MODASSIGN, "'%='") \ macro(MODASSIGN, "'%='") \
macro(POWASSIGN, "'**='") \ range(ASSIGNMENT_LAST, MODASSIGN)
range(ASSIGNMENT_LAST, POWASSIGN)
#define TOKEN_KIND_RANGE_EMIT_NONE(name, value) #define TOKEN_KIND_RANGE_EMIT_NONE(name, value)
#define FOR_EACH_TOKEN_KIND(macro) \ #define FOR_EACH_TOKEN_KIND(macro) \

View File

@ -1509,10 +1509,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
goto out; goto out;
case '*': case '*':
if (matchChar('*')) tp->type = matchChar('=') ? TOK_MULASSIGN : TOK_MUL;
tp->type = matchChar('=') ? TOK_POWASSIGN : TOK_POW;
else
tp->type = matchChar('=') ? TOK_MULASSIGN : TOK_MUL;
goto out; goto out;
case '/': case '/':

View File

@ -1598,12 +1598,6 @@ BaselineCompiler::emit_JSOP_MOD()
return emitBinaryArith(); return emitBinaryArith();
} }
bool
BaselineCompiler::emit_JSOP_POW()
{
return emitBinaryArith();
}
bool bool
BaselineCompiler::emitBinaryArith() BaselineCompiler::emitBinaryArith()
{ {

View File

@ -80,7 +80,6 @@ namespace jit {
_(JSOP_MUL) \ _(JSOP_MUL) \
_(JSOP_DIV) \ _(JSOP_DIV) \
_(JSOP_MOD) \ _(JSOP_MOD) \
_(JSOP_POW) \
_(JSOP_LT) \ _(JSOP_LT) \
_(JSOP_LE) \ _(JSOP_LE) \
_(JSOP_GT) \ _(JSOP_GT) \

View File

@ -1905,10 +1905,6 @@ DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallbac
if (!ModValues(cx, &lhsCopy, &rhsCopy, ret)) if (!ModValues(cx, &lhsCopy, &rhsCopy, ret))
return false; return false;
break; break;
case JSOP_POW:
if (!math_pow_handle(cx, lhsCopy, rhsCopy, ret))
return false;
break;
case JSOP_BITOR: { case JSOP_BITOR: {
int32_t result; int32_t result;
if (!BitOr(cx, lhs, rhs, &result)) if (!BitOr(cx, lhs, rhs, &result))
@ -2042,7 +2038,7 @@ DoBinaryArithFallback(JSContext* cx, BaselineFrame* frame, ICBinaryArith_Fallbac
} }
} }
if (lhs.isInt32() && rhs.isInt32() && op != JSOP_POW) { if (lhs.isInt32() && rhs.isInt32()) {
bool allowDouble = ret.isDouble(); bool allowDouble = ret.isDouble();
if (allowDouble) if (allowDouble)
stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32); stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
@ -10028,7 +10024,7 @@ ICCallStubCompiler::pushSpreadCallArguments(MacroAssembler& masm,
masm.unboxObject(Address(masm.getStackPointer(), masm.unboxObject(Address(masm.getStackPointer(),
(isConstructing * sizeof(Value)) + STUB_FRAME_SIZE), startReg); (isConstructing * sizeof(Value)) + STUB_FRAME_SIZE), startReg);
masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg); masm.loadPtr(Address(startReg, NativeObject::offsetOfElements()), startReg);
// Align the stack such that the JitFrameLayout is aligned on the // Align the stack such that the JitFrameLayout is aligned on the
// JitStackAlignment. // JitStackAlignment.
if (isJitCall) { if (isJitCall) {
@ -10278,18 +10274,18 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
// Use BaselineFrameReg instead of BaselineStackReg, because // Use BaselineFrameReg instead of BaselineStackReg, because
// BaselineFrameReg and BaselineStackReg hold the same value just after // BaselineFrameReg and BaselineStackReg hold the same value just after
// calling enterStubFrame. // calling enterStubFrame.
// newTarget // newTarget
if (isConstructing_) if (isConstructing_)
masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE)); masm.pushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE));
// array // array
uint32_t valueOffset = isConstructing_; uint32_t valueOffset = isConstructing_;
masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE)); masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
// this // this
masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE)); masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));
// callee // callee
masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE)); masm.pushValue(Address(BaselineFrameReg, valueOffset++ * sizeof(Value) + STUB_FRAME_SIZE));

View File

@ -1657,9 +1657,6 @@ IonBuilder::inspectOpcode(JSOp op)
case JSOP_MOD: case JSOP_MOD:
return jsop_binary(op); return jsop_binary(op);
case JSOP_POW:
return jsop_pow();
case JSOP_POS: case JSOP_POS:
return jsop_pos(); return jsop_pos();
@ -4600,25 +4597,6 @@ IonBuilder::jsop_binary(JSOp op, MDefinition* left, MDefinition* right)
return maybeInsertResume(); return maybeInsertResume();
} }
bool
IonBuilder::jsop_pow()
{
MDefinition* exponent = current->pop();
MDefinition* base = current->pop();
if (inlineMathPowHelper(base, exponent, MIRType_Double) == InliningStatus_Inlined) {
base->setImplicitlyUsedUnchecked();
exponent->setImplicitlyUsedUnchecked();
return true;
}
// For now, use MIRType_Double, as a safe cover-all. See bug 1188079.
MPow* pow = MPow::New(alloc(), base, exponent, MIRType_Double);
current->add(pow);
current->push(pow);
return true;
}
bool bool
IonBuilder::jsop_binary(JSOp op) IonBuilder::jsop_binary(JSOp op)
{ {

View File

@ -624,7 +624,6 @@ class IonBuilder
bool jsop_bitop(JSOp op); bool jsop_bitop(JSOp op);
bool jsop_binary(JSOp op); bool jsop_binary(JSOp op);
bool jsop_binary(JSOp op, MDefinition* left, MDefinition* right); bool jsop_binary(JSOp op, MDefinition* left, MDefinition* right);
bool jsop_pow();
bool jsop_pos(); bool jsop_pos();
bool jsop_neg(); bool jsop_neg();
bool jsop_setarg(uint32_t arg); bool jsop_setarg(uint32_t arg);
@ -757,7 +756,6 @@ class IonBuilder
InliningStatus inlineMathHypot(CallInfo& callInfo); InliningStatus inlineMathHypot(CallInfo& callInfo);
InliningStatus inlineMathMinMax(CallInfo& callInfo, bool max); InliningStatus inlineMathMinMax(CallInfo& callInfo, bool max);
InliningStatus inlineMathPow(CallInfo& callInfo); InliningStatus inlineMathPow(CallInfo& callInfo);
InliningStatus inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outputType);
InliningStatus inlineMathRandom(CallInfo& callInfo); InliningStatus inlineMathRandom(CallInfo& callInfo);
InliningStatus inlineMathImul(CallInfo& callInfo); InliningStatus inlineMathImul(CallInfo& callInfo);
InliningStatus inlineMathFRound(CallInfo& callInfo); InliningStatus inlineMathFRound(CallInfo& callInfo);

View File

@ -1347,11 +1347,17 @@ IonBuilder::inlineMathHypot(CallInfo& callInfo)
} }
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outputType) IonBuilder::inlineMathPow(CallInfo& callInfo)
{ {
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
// Typechecking. // Typechecking.
MIRType baseType = lhs->type(); MIRType baseType = callInfo.getArg(0)->type();
MIRType powerType = rhs->type(); MIRType powerType = callInfo.getArg(1)->type();
MIRType outputType = getInlineReturnType();
if (outputType != MIRType_Int32 && outputType != MIRType_Double) if (outputType != MIRType_Int32 && outputType != MIRType_Double)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
@ -1360,13 +1366,17 @@ IonBuilder::inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outp
if (!IsNumberType(powerType)) if (!IsNumberType(powerType))
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
MDefinition* base = lhs; callInfo.setImplicitlyUsedUnchecked();
MDefinition* power = rhs;
MDefinition* base = callInfo.getArg(0);
MDefinition* power = callInfo.getArg(1);
MDefinition* output = nullptr; MDefinition* output = nullptr;
// Optimize some constant powers. // Optimize some constant powers.
if (rhs->isConstantValue() && rhs->constantValue().isNumber()) { if (callInfo.getArg(1)->isConstantValue() &&
double pow = rhs->constantValue().toNumber(); callInfo.getArg(1)->constantValue().isNumber())
{
double pow = callInfo.getArg(1)->constantValue().toNumber();
// Math.pow(x, 0.5) is a sqrt with edge-case detection. // Math.pow(x, 0.5) is a sqrt with edge-case detection.
if (pow == 0.5) { if (pow == 0.5) {
@ -1441,23 +1451,6 @@ IonBuilder::inlineMathPowHelper(MDefinition* lhs, MDefinition* rhs, MIRType outp
return InliningStatus_Inlined; return InliningStatus_Inlined;
} }
IonBuilder::InliningStatus
IonBuilder::inlineMathPow(CallInfo& callInfo)
{
if (callInfo.argc() != 2 || callInfo.constructing()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
IonBuilder::InliningStatus status =
inlineMathPowHelper(callInfo.getArg(0), callInfo.getArg(1), getInlineReturnType());
if (status == IonBuilder::InliningStatus_Inlined)
callInfo.setImplicitlyUsedUnchecked();
return status;
}
IonBuilder::InliningStatus IonBuilder::InliningStatus
IonBuilder::inlineMathRandom(CallInfo& callInfo) IonBuilder::inlineMathRandom(CallInfo& callInfo)
{ {

View File

@ -1,103 +0,0 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
var BUGNUMBER = 1135708;
var summary = "Implement the exponentiation operator";
print(BUGNUMBER + ": " + summary);
// Constant folding
assertEq(2 ** 2 ** 3, 256);
assertEq(1 ** 1 ** 4, 1);
// No folding
var two = 2;
var three = 3;
var four = 4;
assertEq(two ** two ** three, 256);
assertEq(1 ** 1 ** four, 1);
// Operator precedence
assertEq(2 ** 3 / 2 ** 3, 1);
assertEq(2 ** 3 * 2 ** 3, 64);
assertEq(2 ** 3 + 2 ** 3, 16);
// With parentheses
assertEq((2 ** 3) ** 2, 64);
assertEq(2 ** (3 ** 2), 512);
// Assignment operator
var x = 2;
assertEq(x **= 2 ** 3, 256);
assertEq(x, 256);
// Loop to test baseline and ION
for (var i=0; i<10000; i++) {
assertEq((2 ** 3) ** 2, 64);
assertEq(2 ** (3 ** 2), 512);
var x = 2;
assertEq(x **= 2 ** 3, 256);
assertEq(x, 256);
}
// Comments should not be confused with exp operator
var a, c, e;
a = c = e = 2;
assertEq(a**/**b**/c/**/**/**d**/e, 16);
// Two stars separated should not parse as exp operator
assertThrows(function() { return Reflect.parse("2 * * 3"); }, SyntaxError);
// Check if error propagation works
var thrower = {
get value() {
throw new Error();
}
};
assertThrowsInstanceOf(function() { return thrower.value ** 2; }, Error);
assertThrowsInstanceOf(function() { return 2 ** thrower.value; }, Error);
assertThrowsInstanceOf(function() { return 2 ** thrower.value ** 2; }, Error);
var convertibleToPrimitive = {
valueOf: function() {
throw new Error("oops");
}
};
assertThrowsInstanceOf(function() { return convertibleToPrimitive ** 3; }, Error);
assertThrowsInstanceOf(function() { return 3 ** convertibleToPrimitive; }, Error);
assertEq(NaN ** 2, NaN);
assertEq(2 ** NaN, NaN);
assertEq(2 ** "3", 8);
assertEq("2" ** 3, 8);
// Reflect.parse generates a correct parse tree for simplest case
var parseTree = Reflect.parse("a ** b");
assertEq(parseTree.body[0].type, "ExpressionStatement");
assertEq(parseTree.body[0].expression.operator, "**");
assertEq(parseTree.body[0].expression.left.name, "a");
assertEq(parseTree.body[0].expression.right.name, "b");
// Reflect.parse generates a tree following the right-associativity rule
var parseTree = Reflect.parse("a ** b ** c");
assertEq(parseTree.body[0].type, "ExpressionStatement");
assertEq(parseTree.body[0].expression.left.name, "a");
assertEq(parseTree.body[0].expression.right.operator, "**");
assertEq(parseTree.body[0].expression.right.left.name, "b");
assertEq(parseTree.body[0].expression.right.right.name, "c");
function assertTrue(v) {
assertEq(v, true);
}
function assertFalse(v) {
assertEq(v, false);
}
if (typeof reportCompare === "function")
reportCompare(true, true);

View File

@ -2052,6 +2052,7 @@ CASE(EnableInterruptsPseudoOpcode)
CASE(JSOP_NOP) CASE(JSOP_NOP)
CASE(JSOP_UNUSED2) CASE(JSOP_UNUSED2)
CASE(JSOP_BACKPATCH) CASE(JSOP_BACKPATCH)
CASE(JSOP_UNUSED150)
CASE(JSOP_UNUSED161) CASE(JSOP_UNUSED161)
CASE(JSOP_UNUSED162) CASE(JSOP_UNUSED162)
CASE(JSOP_UNUSED163) CASE(JSOP_UNUSED163)
@ -2654,17 +2655,6 @@ CASE(JSOP_MOD)
} }
END_CASE(JSOP_MOD) END_CASE(JSOP_MOD)
CASE(JSOP_POW)
{
ReservedRooted<Value> lval(&rootValue0, REGS.sp[-2]);
ReservedRooted<Value> rval(&rootValue1, REGS.sp[-1]);
MutableHandleValue res = REGS.stackHandleAt(-2);
if (!math_pow_handle(cx, lval, rval, res))
goto error;
REGS.sp--;
}
END_CASE(JSOP_POW)
CASE(JSOP_NOT) CASE(JSOP_NOT)
{ {
bool cond = ToBoolean(REGS.stackHandleAt(-1)); bool cond = ToBoolean(REGS.stackHandleAt(-1));

View File

@ -1533,15 +1533,7 @@
* Stack: => * Stack: =>
*/ \ */ \
macro(JSOP_BACKPATCH, 149,"backpatch", NULL, 5, 0, 0, JOF_JUMP) \ macro(JSOP_BACKPATCH, 149,"backpatch", NULL, 5, 0, 0, JOF_JUMP) \
/* macro(JSOP_UNUSED150, 150,"unused150", NULL, 1, 0, 0, JOF_BYTE) \
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
* the result of 'Math.pow(lval, rval)'.
* Category: Operators
* Type: Arithmetic Operators
* Operands:
* Stack: lval, rval => (lval ** rval)
*/ \
macro(JSOP_POW, 150, "pow", "**", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
\ \
/* /*
* Pops the top of stack value as 'v', sets pending exception as 'v', * Pops the top of stack value as 'v', sets pending exception as 'v',

View File

@ -29,7 +29,7 @@ namespace js {
* *
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/ */
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 299; static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 298;
static const uint32_t XDR_BYTECODE_VERSION = static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND); uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);