Bug 1130811 - Always use list nodes (albeit in some circumstances with only two elements), and never binary nodes, to represent various binary operations. r=luke

--HG--
extra : rebase_source : 108e47ceebb0fa680dc3e1cba151441aeb5b3a4c
This commit is contained in:
Jeff Walden 2015-02-10 00:58:11 -08:00
Родитель 10d2a6c34f
Коммит 45a6d07759
9 изменённых файлов: 267 добавлений и 278 удалений

Просмотреть файл

@ -183,6 +183,114 @@ CaseBody(ParseNode *pn)
return BinaryRight(pn);
}
static inline ParseNode *
BinaryOpLeft(ParseNode *pn)
{
MOZ_ASSERT(pn->isBinaryOperation());
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count == 2);
return ListHead(pn);
}
static inline ParseNode *
BinaryOpRight(ParseNode *pn)
{
MOZ_ASSERT(pn->isBinaryOperation());
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_count == 2);
return NextNode(ListHead(pn));
}
static inline ParseNode *
BitwiseLeft(ParseNode *pn)
{
return BinaryOpLeft(pn);
}
static inline ParseNode *
BitwiseRight(ParseNode *pn)
{
return BinaryOpRight(pn);
}
static inline ParseNode *
MultiplyLeft(ParseNode *pn)
{
MOZ_ASSERT(pn->isKind(PNK_STAR));
return BinaryOpLeft(pn);
}
static inline ParseNode *
MultiplyRight(ParseNode *pn)
{
MOZ_ASSERT(pn->isKind(PNK_STAR));
return BinaryOpRight(pn);
}
static inline ParseNode *
AddSubLeft(ParseNode *pn)
{
MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
return BinaryOpLeft(pn);
}
static inline ParseNode *
AddSubRight(ParseNode *pn)
{
MOZ_ASSERT(pn->isKind(PNK_ADD) || pn->isKind(PNK_SUB));
return BinaryOpRight(pn);
}
static inline ParseNode *
DivOrModLeft(ParseNode *pn)
{
MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
return BinaryOpLeft(pn);
}
static inline ParseNode *
DivOrModRight(ParseNode *pn)
{
MOZ_ASSERT(pn->isKind(PNK_DIV) || pn->isKind(PNK_MOD));
return BinaryOpRight(pn);
}
static inline ParseNode *
ComparisonLeft(ParseNode *pn)
{
return BinaryOpLeft(pn);
}
static inline ParseNode *
ComparisonRight(ParseNode *pn)
{
return BinaryOpRight(pn);
}
static inline ParseNode *
AndOrLeft(ParseNode *pn)
{
return BinaryOpLeft(pn);
}
static inline ParseNode *
AndOrRight(ParseNode *pn)
{
return BinaryOpRight(pn);
}
static inline ParseNode *
RelationalLeft(ParseNode *pn)
{
return BinaryOpLeft(pn);
}
static inline ParseNode *
RelationalRight(ParseNode *pn)
{
return BinaryOpRight(pn);
}
static inline bool
IsExpressionStatement(ParseNode *pn)
{
@ -3712,13 +3820,13 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c
{
switch (coercionNode->getKind()) {
case PNK_BITOR: {
ParseNode *rhs = BinaryRight(coercionNode);
ParseNode *rhs = BitwiseRight(coercionNode);
uint32_t i;
if (!IsLiteralInt(m, rhs, &i) || i != 0)
return m.fail(rhs, "must use |0 for argument/return coercion");
*coercion = AsmJS_ToInt32;
if (coercedExpr)
*coercedExpr = BinaryLeft(coercionNode);
*coercedExpr = BitwiseLeft(coercionNode);
return true;
}
case PNK_POS: {
@ -4329,8 +4437,10 @@ static bool
FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
NeedsBoundsCheck *needsBoundsCheck)
{
ParseNode *indexNode = BinaryLeft(*indexExpr);
ParseNode *maskNode = BinaryRight(*indexExpr);
MOZ_ASSERT((*indexExpr)->isKind(PNK_BITAND));
ParseNode *indexNode = BitwiseLeft(*indexExpr);
ParseNode *maskNode = BitwiseRight(*indexExpr);
uint32_t mask2;
if (IsLiteralOrConstInt(f, maskNode, &mask2)) {
@ -4388,16 +4498,17 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *viewName, ParseNode *indexExpr,
MDefinition *pointerDef;
if (indexExpr->isKind(PNK_RSH)) {
ParseNode *shiftNode = BinaryRight(indexExpr);
ParseNode *pointerNode = BinaryLeft(indexExpr);
ParseNode *shiftAmountNode = BitwiseRight(indexExpr);
uint32_t shift;
if (!IsLiteralInt(f.m(), shiftNode, &shift))
return f.failf(shiftNode, "shift amount must be constant");
if (!IsLiteralInt(f.m(), shiftAmountNode, &shift))
return f.failf(shiftAmountNode, "shift amount must be constant");
unsigned requiredShift = TypedArrayShift(*viewType);
if (shift != requiredShift)
return f.failf(shiftNode, "shift amount must be %u", requiredShift);
return f.failf(shiftAmountNode, "shift amount must be %u", requiredShift);
ParseNode *pointerNode = BitwiseLeft(indexExpr);
if (pointerNode->isKind(PNK_BITAND))
FoldMaskedArrayIndex(f, &pointerNode, &mask, needsBoundsCheck);
@ -4596,6 +4707,7 @@ static bool
CheckAssign(FunctionCompiler &f, ParseNode *assign, MDefinition **def, Type *type)
{
MOZ_ASSERT(assign->isKind(PNK_ASSIGN));
ParseNode *lhs = BinaryLeft(assign);
ParseNode *rhs = BinaryRight(assign);
@ -5094,8 +5206,8 @@ CheckFuncPtrCall(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDef
if (!indexExpr->isKind(PNK_BITAND))
return f.fail(indexExpr, "function-pointer table index expression needs & mask");
ParseNode *indexNode = BinaryLeft(indexExpr);
ParseNode *maskNode = BinaryRight(indexExpr);
ParseNode *indexNode = BitwiseLeft(indexExpr);
ParseNode *maskNode = BitwiseRight(indexExpr);
uint32_t mask;
if (!IsLiteralInt(f.m(), maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
@ -6287,8 +6399,8 @@ static bool
CheckMultiply(FunctionCompiler &f, ParseNode *star, MDefinition **def, Type *type)
{
MOZ_ASSERT(star->isKind(PNK_STAR));
ParseNode *lhs = BinaryLeft(star);
ParseNode *rhs = BinaryRight(star);
ParseNode *lhs = MultiplyLeft(star);
ParseNode *rhs = MultiplyRight(star);
MDefinition *lhsDef;
Type lhsType;
@ -6330,8 +6442,8 @@ CheckAddOrSub(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *typ
JS_CHECK_RECURSION_DONT_REPORT(f.cx(), return f.m().failOverRecursed());
MOZ_ASSERT(expr->isKind(PNK_ADD) || expr->isKind(PNK_SUB));
ParseNode *lhs = BinaryLeft(expr);
ParseNode *rhs = BinaryRight(expr);
ParseNode *lhs = AddSubLeft(expr);
ParseNode *rhs = AddSubRight(expr);
MDefinition *lhsDef, *rhsDef;
Type lhsType, rhsType;
@ -6392,8 +6504,9 @@ static bool
CheckDivOrMod(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type)
{
MOZ_ASSERT(expr->isKind(PNK_DIV) || expr->isKind(PNK_MOD));
ParseNode *lhs = BinaryLeft(expr);
ParseNode *rhs = BinaryRight(expr);
ParseNode *lhs = DivOrModLeft(expr);
ParseNode *rhs = DivOrModRight(expr);
MDefinition *lhsDef, *rhsDef;
Type lhsType, rhsType;
@ -6446,8 +6559,9 @@ CheckComparison(FunctionCompiler &f, ParseNode *comp, MDefinition **def, Type *t
{
MOZ_ASSERT(comp->isKind(PNK_LT) || comp->isKind(PNK_LE) || comp->isKind(PNK_GT) ||
comp->isKind(PNK_GE) || comp->isKind(PNK_EQ) || comp->isKind(PNK_NE));
ParseNode *lhs = BinaryLeft(comp);
ParseNode *rhs = BinaryRight(comp);
ParseNode *lhs = ComparisonLeft(comp);
ParseNode *rhs = ComparisonRight(comp);
MDefinition *lhsDef, *rhsDef;
Type lhsType, rhsType;
@ -6484,8 +6598,8 @@ CheckComparison(FunctionCompiler &f, ParseNode *comp, MDefinition **def, Type *t
static bool
CheckBitwise(FunctionCompiler &f, ParseNode *bitwise, MDefinition **def, Type *type)
{
ParseNode *lhs = BinaryLeft(bitwise);
ParseNode *rhs = BinaryRight(bitwise);
ParseNode *lhs = BitwiseLeft(bitwise);
ParseNode *rhs = BitwiseRight(bitwise);
int32_t identityElement;
bool onlyOnRight;
@ -7208,20 +7322,20 @@ static bool
CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBufferName,
uint32_t *mask, uint32_t *minLength, uint32_t *maxLength)
{
if (!cond->isKind(PNK_OR) || !BinaryLeft(cond)->isKind(PNK_OR))
if (!cond->isKind(PNK_OR) || !AndOrLeft(cond)->isKind(PNK_OR))
return m.fail(cond, "expecting byteLength & K || byteLength <= L || byteLength > M");
ParseNode *cond1 = BinaryLeft(BinaryLeft(cond));
ParseNode *cond2 = BinaryRight(BinaryLeft(cond));
ParseNode *cond3 = BinaryRight(cond);
ParseNode *cond1 = AndOrLeft(AndOrLeft(cond));
ParseNode *cond2 = AndOrRight(AndOrLeft(cond));
ParseNode *cond3 = AndOrRight(cond);
if (!cond1->isKind(PNK_BITAND))
return m.fail(cond1, "expecting byteLength & K");
if (!CheckByteLengthCall(m, BinaryLeft(cond1), newBufferName))
if (!CheckByteLengthCall(m, BitwiseLeft(cond1), newBufferName))
return false;
ParseNode *maskNode = BinaryRight(cond1);
ParseNode *maskNode = BitwiseRight(cond1);
if (!IsLiteralInt(m, maskNode, mask))
return m.fail(maskNode, "expecting integer literal mask");
if ((*mask & 0xffffff) != 0xffffff)
@ -7230,10 +7344,10 @@ CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBu
if (!cond2->isKind(PNK_LE))
return m.fail(cond2, "expecting byteLength <= L");
if (!CheckByteLengthCall(m, BinaryLeft(cond2), newBufferName))
if (!CheckByteLengthCall(m, RelationalLeft(cond2), newBufferName))
return false;
ParseNode *minLengthNode = BinaryRight(cond2);
ParseNode *minLengthNode = RelationalRight(cond2);
uint32_t minLengthExclusive;
if (!IsLiteralInt(m, minLengthNode, &minLengthExclusive))
return m.fail(minLengthNode, "expecting integer literal");
@ -7246,10 +7360,10 @@ CheckHeapLengthCondition(ModuleCompiler &m, ParseNode *cond, PropertyName *newBu
if (!cond3->isKind(PNK_GT))
return m.fail(cond3, "expecting byteLength > M");
if (!CheckByteLengthCall(m, BinaryLeft(cond3), newBufferName))
if (!CheckByteLengthCall(m, RelationalLeft(cond3), newBufferName))
return false;
ParseNode *maxLengthNode = BinaryRight(cond3);
ParseNode *maxLengthNode = RelationalRight(cond3);
if (!IsLiteralInt(m, maxLengthNode, maxLength))
return m.fail(maxLengthNode, "expecting integer literal");
if (*maxLength > 0x80000000)

Просмотреть файл

@ -2039,15 +2039,10 @@ CheckSideEffects(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool
return true;
}
if (pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) || pn->isOp(JSOP_STRICTEQ) ||
pn->isOp(JSOP_STRICTNE)) {
/*
* ||, &&, ===, and !== do not convert their operands via
* toString or valueOf method calls.
*/
return CheckSideEffects(cx, bce, pn->pn_left, answer) &&
CheckSideEffects(cx, bce, pn->pn_right, answer);
}
MOZ_ASSERT(!pn->isOp(JSOP_OR), "|| produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_AND), "&& produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_STRICTEQ), "=== produces a list now");
MOZ_ASSERT(!pn->isOp(JSOP_STRICTNE), "!== produces a list now");
/*
* We can't easily prove that neither operand ever denotes an
@ -6331,6 +6326,8 @@ EmitCallOrNew(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
static bool
EmitLogical(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
{
MOZ_ASSERT(pn->isArity(PN_LIST));
/*
* JSOP_OR converts the operand on the stack to boolean, leaves the original
* value on the stack and jumps if true; otherwise it falls into the next
@ -6341,26 +6338,6 @@ EmitLogical(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
* otherwise it falls into the right operand's bytecode.
*/
if (pn->isArity(PN_BINARY)) {
if (!EmitTree(cx, bce, pn->pn_left))
return false;
ptrdiff_t top = EmitJump(cx, bce, JSOP_BACKPATCH, 0);
if (top < 0)
return false;
if (Emit1(cx, bce, JSOP_POP) < 0)
return false;
if (!EmitTree(cx, bce, pn->pn_right))
return false;
ptrdiff_t off = bce->offset();
jsbytecode *pc = bce->code(top);
SET_JUMP_OFFSET(pc, off - top);
*pc = pn->getOp();
return true;
}
MOZ_ASSERT(pn->isArity(PN_LIST));
MOZ_ASSERT(pn->pn_head->pn_next->pn_next);
/* Left-associative operator chain: avoid too much recursion. */
ParseNode *pn2 = pn->pn_head;
if (!EmitTree(cx, bce, pn2))
@ -7138,29 +7115,21 @@ frontend::EmitTree(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
case PNK_URSH:
case PNK_STAR:
case PNK_DIV:
case PNK_MOD:
if (pn->isArity(PN_LIST)) {
/* Left-associative operator chain: avoid too much recursion. */
ParseNode *pn2 = pn->pn_head;
if (!EmitTree(cx, bce, pn2))
case PNK_MOD: {
MOZ_ASSERT(pn->isArity(PN_LIST));
/* Left-associative operator chain: avoid too much recursion. */
ParseNode *subexpr = pn->pn_head;
if (!EmitTree(cx, bce, subexpr))
return false;
JSOp op = pn->getOp();
while ((subexpr = subexpr->pn_next) != nullptr) {
if (!EmitTree(cx, bce, subexpr))
return false;
JSOp op = pn->getOp();
while ((pn2 = pn2->pn_next) != nullptr) {
if (!EmitTree(cx, bce, pn2))
return false;
if (Emit1(cx, bce, op) < 0)
return false;
}
} else {
/* Binary operators that evaluate both operands unconditionally. */
if (!EmitTree(cx, bce, pn->pn_left))
return false;
if (!EmitTree(cx, bce, pn->pn_right))
return false;
if (Emit1(cx, bce, pn->getOp()) < 0)
if (Emit1(cx, bce, op) < 0)
return false;
}
break;
}
case PNK_THROW:
case PNK_TYPEOF:

Просмотреть файл

@ -825,92 +825,47 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
case PNK_OR:
case PNK_AND:
if (sc == SyntacticContext::Condition) {
if (pn->isArity(PN_LIST)) {
ParseNode **listp = &pn->pn_head;
MOZ_ASSERT(*listp == pn1);
uint32_t orig = pn->pn_count;
do {
Truthiness t = Boolish(pn1);
if (t == Unknown) {
listp = &pn1->pn_next;
continue;
}
if ((t == Truthy) == pn->isKind(PNK_OR)) {
for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
pn3 = pn2->pn_next;
handler.freeTree(pn2);
--pn->pn_count;
}
pn1->pn_next = nullptr;
break;
}
MOZ_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
if (pn->pn_count == 1)
break;
*listp = pn1->pn_next;
handler.freeTree(pn1);
--pn->pn_count;
} while ((pn1 = *listp) != nullptr);
// We may have to change arity from LIST to BINARY.
pn1 = pn->pn_head;
if (pn->pn_count == 2) {
pn2 = pn1->pn_next;
pn1->pn_next = nullptr;
MOZ_ASSERT(!pn2->pn_next);
pn->setArity(PN_BINARY);
pn->pn_left = pn1;
pn->pn_right = pn2;
} else if (pn->pn_count == 1) {
ReplaceNode(pnp, pn1);
pn = pn1;
} else if (orig != pn->pn_count) {
// Adjust list tail.
pn2 = pn1->pn_next;
for (; pn1; pn2 = pn1, pn1 = pn1->pn_next)
;
pn->pn_tail = &pn2->pn_next;
}
} else {
ParseNode **listp = &pn->pn_head;
MOZ_ASSERT(*listp == pn1);
uint32_t orig = pn->pn_count;
do {
Truthiness t = Boolish(pn1);
if (t != Unknown) {
if ((t == Truthy) == pn->isKind(PNK_OR)) {
handler.freeTree(pn2);
ReplaceNode(pnp, pn1);
pn = pn1;
} else {
MOZ_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
handler.freeTree(pn1);
ReplaceNode(pnp, pn2);
pn = pn2;
}
if (t == Unknown) {
listp = &pn1->pn_next;
continue;
}
if ((t == Truthy) == pn->isKind(PNK_OR)) {
for (pn2 = pn1->pn_next; pn2; pn2 = pn3) {
pn3 = pn2->pn_next;
handler.freeTree(pn2);
--pn->pn_count;
}
pn1->pn_next = nullptr;
break;
}
MOZ_ASSERT((t == Truthy) == pn->isKind(PNK_AND));
if (pn->pn_count == 1)
break;
*listp = pn1->pn_next;
handler.freeTree(pn1);
--pn->pn_count;
} while ((pn1 = *listp) != nullptr);
// We may have to replace a one-element list with its element.
pn1 = pn->pn_head;
if (pn->pn_count == 1) {
ReplaceNode(pnp, pn1);
pn = pn1;
} else if (orig != pn->pn_count) {
// Adjust list tail.
pn2 = pn1->pn_next;
for (; pn1; pn2 = pn1, pn1 = pn1->pn_next)
continue;
pn->pn_tail = &pn2->pn_next;
}
}
break;
case PNK_SUBASSIGN:
case PNK_BITORASSIGN:
case PNK_BITXORASSIGN:
case PNK_BITANDASSIGN:
case PNK_LSHASSIGN:
case PNK_RSHASSIGN:
case PNK_URSHASSIGN:
case PNK_MULASSIGN:
case PNK_DIVASSIGN:
case PNK_MODASSIGN:
/*
* Compound operators such as *= should be subject to folding, in case
* the left-hand side is constant, and so that the decompiler produces
* the same string that you get from decompiling a script or function
* compiled from that same string. += is special and so must be
* handled below.
*/
goto do_binary_op;
case PNK_ADDASSIGN:
MOZ_ASSERT(pn->isOp(JSOP_ADD));
/* FALL THROUGH */
case PNK_ADD:
if (pn->isArity(PN_LIST)) {
bool folded = false;
@ -1029,7 +984,13 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
}
/* Can't concatenate string literals, let's try numbers. */
goto do_binary_op;
if (!FoldType(cx, pn1, PNK_NUMBER) || !FoldType(cx, pn2, PNK_NUMBER))
return false;
if (pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)) {
if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn))
return false;
}
break;
case PNK_SUB:
case PNK_STAR:
@ -1038,39 +999,27 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
case PNK_URSH:
case PNK_DIV:
case PNK_MOD:
do_binary_op:
if (pn->isArity(PN_LIST)) {
MOZ_ASSERT(pn->pn_count > 2);
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
if (!FoldType(cx, pn2, PNK_NUMBER))
return false;
}
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
/* XXX fold only if all operands convert to number */
if (!pn2->isKind(PNK_NUMBER))
break;
}
if (!pn2) {
JSOp op = pn->getOp();
pn2 = pn1->pn_next;
pn3 = pn2->pn_next;
if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn))
return false;
while ((pn2 = pn3) != nullptr) {
pn3 = pn2->pn_next;
if (!FoldBinaryNumeric(cx, op, pn, pn2, pn))
return false;
}
}
} else {
MOZ_ASSERT(pn->isArity(PN_BINARY));
if (!FoldType(cx, pn1, PNK_NUMBER) ||
!FoldType(cx, pn2, PNK_NUMBER)) {
MOZ_ASSERT(pn->getArity() == PN_LIST);
MOZ_ASSERT(pn->pn_count >= 2);
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
if (!FoldType(cx, pn2, PNK_NUMBER))
return false;
}
if (pn1->isKind(PNK_NUMBER) && pn2->isKind(PNK_NUMBER)) {
if (!FoldBinaryNumeric(cx, pn->getOp(), pn1, pn2, pn))
}
for (pn2 = pn1; pn2; pn2 = pn2->pn_next) {
/* XXX fold only if all operands convert to number */
if (!pn2->isKind(PNK_NUMBER))
break;
}
if (!pn2) {
JSOp op = pn->getOp();
pn2 = pn1->pn_next;
pn3 = pn2->pn_next;
if (!FoldBinaryNumeric(cx, op, pn1, pn2, pn))
return false;
while ((pn2 = pn3) != nullptr) {
pn3 = pn2->pn_next;
if (!FoldBinaryNumeric(cx, op, pn, pn2, pn))
return false;
}
}

Просмотреть файл

@ -217,10 +217,10 @@ class FullParseHandler
TokenPos pos(left->pn_pos.begin, right->pn_pos.end);
return new_<BinaryNode>(kind, op, pos, left, right);
}
ParseNode *newBinaryOrAppend(ParseNodeKind kind, ParseNode *left, ParseNode *right,
ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP)
ParseNode *appendOrCreateList(ParseNodeKind kind, ParseNode *left, ParseNode *right,
ParseContext<FullParseHandler> *pc, JSOp op = JSOP_NOP)
{
return ParseNode::newBinaryOrAppend(kind, op, left, right, this, pc, foldConstants);
return ParseNode::appendOrCreateList(kind, op, left, right, this, pc, foldConstants);
}
ParseNode *newTernary(ParseNodeKind kind,
@ -559,7 +559,7 @@ class FullParseHandler
ParseNode *newAssignment(ParseNodeKind kind, ParseNode *lhs, ParseNode *rhs,
ParseContext<FullParseHandler> *pc, JSOp op)
{
return newBinaryOrAppend(kind, lhs, rhs, pc, op);
return newBinary(kind, lhs, rhs, op);
}
bool isUnparenthesizedYieldExpression(ParseNode *node) {

Просмотреть файл

@ -245,54 +245,37 @@ ParseNodeAllocator::allocNode()
}
ParseNode *
ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
FullParseHandler *handler)
ParseNode::appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
bool foldConstants)
{
if (!left || !right)
return nullptr;
// The asm.js specification is written in ECMAScript grammar terms that
// specify *only* a binary tree. It's a royal pain to implement the asm.js
// spec to act upon n-ary lists as created below. So for asm.js, form a
// binary tree of lists exactly as ECMAScript would by skipping the
// following optimization.
if (!pc->useAsmOrInsideUseAsm()) {
// Left-associative trees of a given operator (e.g. |a + b + c|) are
// binary trees in the spec: (+ (+ a b) c) in Lisp terms. Recursively
// 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
// such operations: (+ a b c).
if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
ListNode *list = &left->as<ListNode>();
MOZ_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));
list->append(right);
list->pn_pos.end = right->pn_pos.end;
ListNode *list;
if (left->pn_arity == PN_LIST) {
list = &left->as<ListNode>();
} else {
ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
list = handler->new_<ListNode>(kind, op, pn1);
if (!list)
return nullptr;
list->append(pn2);
return list;
}
}
list->append(right);
list->pn_pos.end = right->pn_pos.end;
return list;
}
ParseNode *
ParseNode::newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
bool foldConstants)
{
if (!left || !right)
ParseNode *list = handler->new_<ListNode>(kind, op, left);
if (!list)
return nullptr;
/*
* Ensure that the parse tree is faithful to the source when "use asm" (for
* the purpose of type checking).
*/
if (pc->useAsmOrInsideUseAsm())
return handler->new_<BinaryNode>(kind, op, left, right);
/*
* Flatten a left-associative (left-heavy) tree of a given operator into
* a list to reduce js::FoldConstants and js::frontend::EmitTree recursion.
*/
if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC))
return append(kind, op, left, right, handler);
return handler->new_<BinaryNode>(kind, op, left, right);
list->append(right);
return list;
}
const char *

Просмотреть файл

@ -510,6 +510,11 @@ class ParseNode
return PNK_ASSIGNMENT_START <= kind && kind <= PNK_ASSIGNMENT_LAST;
}
bool isBinaryOperation() const {
ParseNodeKind kind = getKind();
return PNK_BINOP_FIRST <= kind && kind <= PNK_BINOP_LAST;
}
/* Boolean attributes. */
bool isInParens() const { return pn_parens; }
bool isLikelyIIFE() const { return isInParens(); }
@ -641,21 +646,13 @@ class ParseNode
public:
/*
* Append right to left, forming a list node. |left| must have the given
* kind and op, and op must be left-associative.
* If |left| is a list of the given kind/left-associative op, append
* |right| to it and return |left|. Otherwise return a [left, right] list.
*/
static ParseNode *
append(ParseNodeKind tt, JSOp op, ParseNode *left, ParseNode *right, FullParseHandler *handler);
/*
* Either append right to left, if left meets the conditions necessary to
* append (see append), or form a binary node whose children are right and
* left.
*/
static ParseNode *
newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
bool foldConstants);
appendOrCreateList(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
FullParseHandler *handler, ParseContext<FullParseHandler> *pc,
bool foldConstants);
inline PropertyName *name() const;
inline JSAtom *atom() const;

Просмотреть файл

@ -3881,7 +3881,7 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool *psimple,
if (!bindBeforeInitializer && !checkDestructuring(&data, pn2))
return null();
pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc);
pn2 = handler.newBinary(PNK_ASSIGN, pn2, init);
if (!pn2)
return null();
handler.addList(pn, pn2);
@ -6083,7 +6083,7 @@ Parser<ParseHandler>::orExpr1(InvokedPrediction invoked)
depth--;
ParseNodeKind combiningPnk = kindStack[depth];
JSOp combiningOp = BinaryOpParseNodeKindToJSOp(combiningPnk);
pn = handler.newBinaryOrAppend(combiningPnk, nodeStack[depth], pn, pc, combiningOp);
pn = handler.appendOrCreateList(combiningPnk, nodeStack[depth], pn, pc, combiningOp);
if (!pn)
return pn;
}

Просмотреть файл

@ -163,8 +163,8 @@ class SyntaxParseHandler
Node newBinary(ParseNodeKind kind, Node left, Node right, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
Node newBinaryOrAppend(ParseNodeKind kind, Node left, Node right,
ParseContext<SyntaxParseHandler> *pc, JSOp op = JSOP_NOP) {
Node appendOrCreateList(ParseNodeKind kind, Node left, Node right,
ParseContext<SyntaxParseHandler> *pc, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
@ -292,7 +292,7 @@ class SyntaxParseHandler
{
if (kind == PNK_ASSIGN)
return NodeUnparenthesizedAssignment;
return newBinaryOrAppend(kind, lhs, rhs, pc, op);
return newBinary(kind, lhs, rhs, op);
}
bool isUnparenthesizedYieldExpression(Node node) {

Просмотреть файл

@ -2756,18 +2756,7 @@ ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
case PNK_OR:
case PNK_AND:
{
if (pn->isArity(PN_BINARY)) {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
RootedValue left(cx), right(cx);
return expression(pn->pn_left, &left) &&
expression(pn->pn_right, &right) &&
builder.logicalExpression(pn->isKind(PNK_OR), left, right, &pn->pn_pos, dst);
}
return leftAssociate(pn, dst);
}
case PNK_PREINCREMENT:
case PNK_PREDECREMENT:
@ -2837,18 +2826,6 @@ ASTSerializer::expression(ParseNode *pn, MutableHandleValue dst)
case PNK_BITAND:
case PNK_IN:
case PNK_INSTANCEOF:
if (pn->isArity(PN_BINARY)) {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_right->pn_pos));
BinaryOperator op = binop(pn->getKind(), pn->getOp());
LOCAL_ASSERT(op > BINOP_ERR && op < BINOP_LIMIT);
RootedValue left(cx), right(cx);
return expression(pn->pn_left, &left) &&
expression(pn->pn_right, &right) &&
builder.binaryExpression(op, left, right, &pn->pn_pos, dst);
}
return leftAssociate(pn, dst);
case PNK_DELETE: