Index: src/x64/fast-codegen-x64.cc |
=================================================================== |
--- src/x64/fast-codegen-x64.cc (revision 3171) |
+++ src/x64/fast-codegen-x64.cc (working copy) |
@@ -593,7 +593,7 @@ |
// Push function on the stack. |
Visit(node->expression()); |
ASSERT(node->expression()->location().is_value()); |
- // If location is temporary, already on the stack, |
+ // If location is value, already on the stack, |
// Push global object (receiver). |
__ push(CodeGenerator::GlobalObject()); |
@@ -604,7 +604,7 @@ |
for (int i = 0; i < arg_count; i++) { |
Visit(args->at(i)); |
ASSERT(args->at(i)->location().is_value()); |
- // If location is temporary, it is already on the stack, |
+ // If location is value, it is already on the stack, |
// so nothing to do here. |
} |
@@ -645,13 +645,66 @@ |
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { |
- // Compile a short-circuited boolean or operation in a non-test |
- // context. |
- ASSERT(expr->op() == Token::OR); |
+ switch (expr->op()) { |
+ case Token::COMMA: |
+ ASSERT(expr->left()->location().is_effect()); |
+ ASSERT_EQ(expr->right()->location().type(), expr->location().type()); |
+ Visit(expr->left()); |
+ Visit(expr->right()); |
+ break; |
+ |
+ case Token::OR: |
+ case Token::AND: |
+ EmitLogicalOperation(expr); |
+ break; |
+ |
+ case Token::ADD: |
+ case Token::SUB: |
+ case Token::DIV: |
+ case Token::MOD: |
+ case Token::MUL: |
+ case Token::BIT_OR: |
+ case Token::BIT_AND: |
+ case Token::BIT_XOR: |
+ case Token::SHL: |
+ case Token::SHR: |
+ case Token::SAR: { |
+ ASSERT(expr->left()->location().is_value()); |
+ ASSERT(expr->right()->location().is_value()); |
+ |
+ Visit(expr->left()); |
+ Visit(expr->right()); |
+ GenericBinaryOpStub stub(expr->op(), |
+ NO_OVERWRITE, |
+ NO_GENERIC_BINARY_FLAGS); |
+ __ CallStub(&stub); |
+ Move(expr->location(), kReturnRegister); |
+ |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ } |
+} |
+ |
+ |
+void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { |
+ // Compile a short-circuited boolean operation in a non-test context. |
+ |
// Compile (e0 || e1) as if it were |
// (let (temp = e0) temp ? temp : e1). |
+ // Compile (e0 && e1) as if it were |
+ // (let (temp = e0) !temp ? temp : e1). |
Label eval_right, done; |
+ Label *left_true, *left_false; // Where to branch to if lhs has that value. |
+ if (expr->op() == Token::OR) { |
+ left_true = &done; |
+ left_false = &eval_right; |
+ } else { |
+ left_true = &eval_right; |
+ left_false = &done; |
+ } |
Location destination = expr->location(); |
Expression* left = expr->left(); |
Expression* right = expr->right(); |
@@ -684,28 +737,32 @@ |
} |
} |
// The left-hand value is in rax. It is also on the stack iff the |
- // destination location is temporary. |
+ // destination location is value. |
// Perform fast checks assumed by the stub. |
// The undefined value is false. |
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
- __ j(equal, &eval_right); |
+ __ j(equal, left_false); |
__ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. |
- __ j(equal, &done); |
+ __ j(equal, left_true); |
__ CompareRoot(rax, Heap::kFalseValueRootIndex); // False is false. |
- __ j(equal, &eval_right); |
+ __ j(equal, left_false); |
ASSERT(kSmiTag == 0); |
__ SmiCompare(rax, Smi::FromInt(0)); // The smi zero is false. |
- __ j(equal, &eval_right); |
+ __ j(equal, left_false); |
Condition is_smi = masm_->CheckSmi(rax); // All other smis are true. |
- __ j(is_smi, &done); |
+ __ j(is_smi, left_true); |
// Call the stub for all other cases. |
__ push(rax); |
ToBooleanStub stub; |
__ CallStub(&stub); |
__ testq(rax, rax); // The stub returns nonzero for true. |
- __ j(not_zero, &done); |
+ if (expr->op() == Token::OR) { |
+ __ j(not_zero, &done); |
+ } else { |
+ __ j(zero, &done); |
+ } |
__ bind(&eval_right); |
// Discard the left-hand value if present on the stack. |