Chromium Code Reviews| Index: src/ia32/fast-codegen-ia32.cc |
| =================================================================== |
| --- src/ia32/fast-codegen-ia32.cc (revision 3182) |
| +++ src/ia32/fast-codegen-ia32.cc (working copy) |
| @@ -108,6 +108,39 @@ |
| } |
| +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); |
|
William Hesse
2009/10/30 12:09:39
Why not
Label save;
TestAndBranch(source, &save, f
Kevin Millikin (Chromium)
2009/10/30 13:45:53
TestAndBranch destroys source.
|
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + __ push(source); |
| + TestAndBranch(source, &discard, false_label_); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + } |
| + } |
| +} |
| + |
| + |
| void FastCodeGenerator::Move(Expression::Context context, Slot* source) { |
| switch (context) { |
| case Expression::kUninitialized: |
| @@ -117,6 +150,12 @@ |
| case Expression::kValue: |
| __ push(Operand(ebp, SlotOffset(source))); |
| break; |
| + case Expression::kTest: // Fall through. |
| + case Expression::kValueTest: // Fall through. |
| + case Expression::kTestValue: |
| + __ mov(eax, Operand(ebp, SlotOffset(source))); |
|
William Hesse
2009/10/30 12:09:39
This could be optimized if TestAndBranch took an o
Kevin Millikin (Chromium)
2009/10/30 13:45:53
TestAndBranch needs the value in a register to com
|
| + Move(context, eax); |
| + break; |
| } |
| } |
| @@ -130,6 +169,12 @@ |
| case Expression::kValue: |
| __ push(Immediate(expr->handle())); |
| break; |
| + case Expression::kTest: // Fall through. |
| + case Expression::kValueTest: // Fall through. |
| + case Expression::kTestValue: |
| + __ mov(eax, expr->handle()); |
| + Move(context, eax); |
| + break; |
| } |
| } |
| @@ -145,10 +190,63 @@ |
| case Expression::kValue: |
| __ mov(Operand(esp, 0), source); |
| break; |
| + case Expression::kTest: |
| + ASSERT(!source.is(esp)); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + TestAndBranch(source, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + __ mov(Operand(esp, 0), source); |
| + TestAndBranch(source, true_label_, &discard); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + __ mov(Operand(esp, 0), source); |
| + TestAndBranch(source, &discard, false_label_); |
| + __ bind(&discard); |
| + __ add(Operand(esp), 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. |
| + __ cmp(source, Factory::undefined_value()); // The undefined value is false. |
| + __ j(equal, false_label); |
| + __ cmp(source, Factory::true_value()); // True is true. |
| + __ j(equal, true_label); |
| + __ cmp(source, Factory::false_value()); // False is false. |
| + __ j(equal, false_label); |
| + ASSERT_EQ(0, kSmiTag); |
| + __ test(source, Operand(source)); // The smi zero is false. |
| + __ j(zero, false_label); |
| + __ test(source, Immediate(kSmiTagMask)); // All other smis are true. |
| + __ j(zero, true_label); |
| + |
| + // Call the stub for all other cases. |
| + __ push(source); |
| + ToBooleanStub stub; |
| + __ CallStub(&stub); |
| + __ test(eax, Operand(eax)); // 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(esi); // The context is the first argument. |
| @@ -350,6 +448,28 @@ |
| case Expression::kValue: |
| if (!result_saved) __ push(eax); |
| break; |
| + case Expression::kTest: |
| + if (result_saved) __ pop(eax); |
| + TestAndBranch(eax, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + if (!result_saved) __ push(eax); |
| + TestAndBranch(eax, true_label_, &discard); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + if (!result_saved) __ push(eax); |
| + TestAndBranch(eax, &discard, false_label_); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| @@ -424,6 +544,28 @@ |
| case Expression::kValue: |
| if (!result_saved) __ push(eax); |
| break; |
| + case Expression::kTest: |
| + if (result_saved) __ pop(eax); |
| + TestAndBranch(eax, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + Label discard; |
| + if (!result_saved) __ push(eax); |
| + TestAndBranch(eax, true_label_, &discard); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + Label discard; |
| + if (!result_saved) __ push(eax); |
| + TestAndBranch(eax, &discard, false_label_); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| @@ -517,6 +659,34 @@ |
| __ mov(eax, Operand(esp, 0)); |
| __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| break; |
| + case Expression::kTest: |
| + // Case 'if (var = temp) ...'. |
| + __ pop(eax); |
| + __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| + TestAndBranch(eax, true_label_, false_label_); |
| + break; |
| + case Expression::kValueTest: { |
| + // Case '(var = temp) || ...' in value context. |
| + Label discard; |
|
William Hesse
2009/10/30 12:09:39
Same comment as above, on optimization.
|
| + __ mov(eax, Operand(esp, 0)); |
| + __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| + TestAndBranch(eax, true_label_, &discard); |
|
William Hesse
2009/10/30 12:09:39
Can we give TestAndBranch a fallthrough label, so
Kevin Millikin (Chromium)
2009/10/30 13:45:53
We'd need a global fallthrough to get the whole be
|
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(false_label_); |
| + break; |
| + } |
| + case Expression::kTestValue: { |
| + // Case '(var = temp) && ...' in value context. |
| + Label discard; |
| + __ mov(eax, Operand(esp, 0)); |
| + __ mov(Operand(ebp, SlotOffset(var->slot())), eax); |
| + TestAndBranch(eax, &discard, false_label_); |
| + __ bind(&discard); |
| + __ add(Operand(esp), Immediate(kPointerSize)); |
| + __ jmp(true_label_); |
| + break; |
| + } |
| } |
| } |
| } |
| @@ -688,90 +858,7 @@ |
| } |
| -void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { |
| - // Compile a short-circuited boolean operation in a non-test context. |
| +#undef __ |
| - // Compile (e0 || e1) or (e0 && e1) as if it were |
| - // (let (temp = e0) temp [or !temp, for &&] ? 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 eax to perform some |
| - // inlined checks assumed by the stub. |
| - |
| - // Compile the left-hand value into eax. Put it on the stack if we may |
| - // need it as the value of the whole expression. |
| - if (left->AsLiteral() != NULL) { |
| - __ mov(eax, left->AsLiteral()->handle()); |
| - if (context == Expression::kValue) __ push(eax); |
| - } else { |
| - Visit(left); |
| - ASSERT_EQ(Expression::kValue, left->context()); |
| - switch (context) { |
| - case Expression::kUninitialized: |
| - UNREACHABLE(); |
| - case Expression::kEffect: |
| - // Pop the left-hand value into eax because we will not need it as the |
| - // final result. |
| - __ pop(eax); |
| - break; |
| - case Expression::kValue: |
| - // Copy the left-hand value into eax because we may need it as the |
| - // final result. |
| - __ mov(eax, Operand(esp, 0)); |
| - break; |
| - } |
| - } |
| - // The left-hand value is in eax. It is also on the stack iff the |
| - // destination location is value. |
| - |
| - // Perform fast checks assumed by the stub. |
| - __ cmp(eax, Factory::undefined_value()); // The undefined value is false. |
| - __ j(equal, left_false); |
| - __ cmp(eax, Factory::true_value()); // True is true. |
| - __ j(equal, left_true); |
| - __ cmp(eax, Factory::false_value()); // False is false. |
| - __ j(equal, left_false); |
| - ASSERT_EQ(0, kSmiTag); |
| - __ test(eax, Operand(eax)); // The smi zero is false. |
| - __ j(zero, left_false); |
| - __ test(eax, Immediate(kSmiTagMask)); // All other smis are true. |
| - __ j(zero, left_true); |
| - |
| - // Call the stub for all other cases. |
| - __ push(eax); |
| - ToBooleanStub stub; |
| - __ CallStub(&stub); |
| - __ test(eax, Operand(eax)); // 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) { |
| - __ add(Operand(esp), Immediate(kPointerSize)); |
| - } |
| - // Save or discard the right-hand value as needed. |
| - Visit(right); |
| - ASSERT_EQ(context, right->context()); |
| - |
| - __ bind(&done); |
| -} |
| - |
| - |
| } } // namespace v8::internal |