Chromium Code Reviews| Index: src/x64/fast-codegen-x64.cc |
| =================================================================== |
| --- src/x64/fast-codegen-x64.cc (revision 3181) |
| +++ src/x64/fast-codegen-x64.cc (working copy) |
| @@ -116,6 +116,41 @@ |
| } |
| + |
| +void FastCodeGenerator::Move(Expression::Context context, Register source) { |
| + switch (context) { |
| + case Expression::kUninitialized: |
| + UNREACHABLE(); |
| + case Expression::kEffect: |
| + break; |
| + case Expression::kValue: |
| + __ push(source); |
| + break; |
| + case Expression::kTest: |
| + TestAndBranch(source, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + __ push(source); |
| + TestAndBranch(source, true_label_, &discard); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + __ push(source); |
| + TestAndBranch(source, &discard, false_label_); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| + } |
| +} |
| + |
| + |
| void FastCodeGenerator::Move(Expression::Context context, Slot* source) { |
| switch (context) { |
| case Expression::kUninitialized: |
| @@ -125,6 +160,12 @@ |
| case Expression::kValue: |
| __ push(Operand(rbp, SlotOffset(source))); |
| break; |
| + case Expression::kTest: // Fall through. |
| + case Expression::kValueTest: // Fall through. |
| + case Expression::kTestValue: |
| + __ movq(rax, Operand(rbp, SlotOffset(source))); |
| + Move(context, rax); |
| + break; |
| } |
| } |
| @@ -138,6 +179,12 @@ |
| case Expression::kValue: |
| __ Push(expr->handle()); |
| break; |
| + case Expression::kTest: // Fall through. |
| + case Expression::kValueTest: // Fall through. |
| + case Expression::kTestValue: |
| + __ Move(rax, expr->handle()); |
| + Move(context, rax); |
| + break; |
| } |
| } |
| @@ -153,10 +200,65 @@ |
| case Expression::kValue: |
| __ movq(Operand(rsp, 0), source); |
| break; |
| + case Expression::kTest: |
| + ASSERT(!source.is(rsp)); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + TestAndBranch(source, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + __ movq(Operand(rsp, 0), source); |
| + TestAndBranch(source, true_label_, &discard); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + __ movq(Operand(rsp, 0), source); |
| + TestAndBranch(source, &discard, false_label_); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| +void FastCodeGenerator::TestAndBranch(Register source, |
| + Label* true_label, |
| + Label* false_label) { |
| + ASSERT_NE(NULL, true_label); |
| + ASSERT_NE(NULL, false_label); |
| + // Use the shared ToBoolean stub to compile the value in the register into |
| + // control flow to the code generator's true and false labels. Perform |
| + // the fast checks assumed by the stub. |
| + |
| + // The undefined value is false. |
| + __ CompareRoot(source, Heap::kUndefinedValueRootIndex); |
| + __ j(equal, false_label); |
| + __ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true. |
| + __ j(equal, true_label); |
| + __ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false. |
| + __ j(equal, false_label); |
| + ASSERT_EQ(0, kSmiTag); |
| + __ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false. |
| + __ j(equal, false_label); |
| + Condition is_smi = masm_->CheckSmi(source); // All other smis are true. |
| + __ j(is_smi, true_label); |
| + |
| + // Call the stub for all other cases. |
| + __ push(source); |
| + ToBooleanStub stub; |
| + __ CallStub(&stub); |
| + __ testq(rax, rax); // The stub returns nonzero for true. |
| + __ j(not_zero, true_label); |
| + __ jmp(false_label); |
| +} |
| + |
| + |
| void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| // Call the runtime to declare the globals. |
| __ push(rsi); // The context is the first argument. |
| @@ -361,6 +463,28 @@ |
| case Expression::kValue: |
| if (!result_saved) __ push(rax); |
| break; |
| + case Expression::kTest: |
| + if (result_saved) __ pop(rax); |
| + TestAndBranch(rax, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + if (!result_saved) __ push(rax); |
| + TestAndBranch(rax, true_label_, &discard); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + if (!result_saved) __ push(rax); |
| + TestAndBranch(rax, &discard, false_label_); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| @@ -435,6 +559,28 @@ |
| case Expression::kValue: |
| if (!result_saved) __ push(rax); |
| break; |
| + case Expression::kTest: |
| + if (result_saved) __ pop(rax); |
| + TestAndBranch(rax, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + if (!result_saved) __ push(rax); |
| + TestAndBranch(rax, true_label_, &discard); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + if (!result_saved) __ push(rax); |
| + TestAndBranch(rax, &discard, false_label_); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| @@ -527,6 +673,34 @@ |
| __ movq(kScratchRegister, Operand(rsp, 0)); |
| __ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister); |
| break; |
| + case Expression::kTest: |
| + // Case 'if (var = temp) ...'. |
| + __ pop(rax); |
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax); |
| + TestAndBranch(rax, true_label_, false_label_); |
|
William Hesse
2009/10/30 12:09:39
Maybe we should have an operation "TestDropAndBran
Kevin Millikin (Chromium)
2009/10/30 13:45:53
Possibly. This whole chunk of platform-specific c
|
| + break; |
| + case Expression::kValueTest: { |
| + // Case '(var = temp) || ...' in value context. |
| + Label discard; |
| + __ movq(rax, Operand(rsp, 0)); |
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax); |
| + TestAndBranch(rax, true_label_, &discard); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + // Case '(var = temp) && ...' in value context. |
| + Label discard; |
| + __ movq(rax, Operand(rsp, 0)); |
| + __ movq(Operand(rbp, SlotOffset(var->slot())), rax); |
| + TestAndBranch(rax, &discard, false_label_); |
| + __ bind(&discard); |
| + __ addq(rsp, Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| } |
| @@ -700,93 +874,4 @@ |
| } |
| -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; |
| - } |
| - Expression::Context context = expr->context(); |
| - Expression* left = expr->left(); |
| - Expression* right = expr->right(); |
| - |
| - // Use the shared ToBoolean stub to find the boolean value of the |
| - // left-hand subexpression. Load the value into rax to perform some |
| - // inlined checks assumed by the stub. |
| - |
| - // Compile the left-hand value into rax. Put it on the stack if we may |
| - // need it as the value of the whole expression. |
| - if (left->AsLiteral() != NULL) { |
| - __ Move(rax, left->AsLiteral()->handle()); |
| - if (context == Expression::kValue) __ push(rax); |
| - } else { |
| - Visit(left); |
| - ASSERT_EQ(Expression::kValue, left->context()); |
| - switch (context) { |
| - case Expression::kUninitialized: |
| - UNREACHABLE(); |
| - case Expression::kEffect: |
| - // Pop the left-hand value into rax because we will not need it as the |
| - // final result. |
| - __ pop(rax); |
| - break; |
| - case Expression::kValue: |
| - // Copy the left-hand value into rax because we may need it as the |
| - // final result. |
| - __ movq(rax, Operand(rsp, 0)); |
| - break; |
| - } |
| - } |
| - // The left-hand value is in rax. It is also on the stack iff the |
| - // destination location is value. |
| - |
| - // Perform fast checks assumed by the stub. |
| - // The undefined value is false. |
| - __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| - __ j(equal, left_false); |
| - __ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true. |
| - __ j(equal, left_true); |
| - __ CompareRoot(rax, Heap::kFalseValueRootIndex); // False is false. |
| - __ j(equal, left_false); |
| - ASSERT(kSmiTag == 0); |
| - __ SmiCompare(rax, Smi::FromInt(0)); // The smi zero is false. |
| - __ j(equal, left_false); |
| - Condition is_smi = masm_->CheckSmi(rax); // All other smis are true. |
| - __ 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. |
| - 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. |
| - if (context == Expression::kValue) { |
| - __ addq(rsp, Immediate(kPointerSize)); |
| - } |
| - // Save or discard the right-hand value as needed. |
| - Visit(right); |
| - ASSERT_EQ(context, right->context()); |
| - |
| - __ bind(&done); |
| -} |
| - |
| - |
| } } // namespace v8::internal |