зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
10d2a6c34f
Коммит
45a6d07759
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче