Chromium Code Reviews| Index: src/full-codegen.cc | 
| =================================================================== | 
| --- src/full-codegen.cc (revision 8079) | 
| +++ src/full-codegen.cc (working copy) | 
| @@ -702,143 +702,110 @@ | 
| void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) { | 
| Comment cmnt(masm_, "[ BinaryOperation"); | 
| 
 
Kevin Millikin (Chromium)
2011/05/31 11:46:28
By moving this comment into VisitComma, VisitLogic
 
Sven Panne
2011/05/31 14:30:33
Done.
 
 | 
| + switch (expr->op()) { | 
| + case Token::COMMA: return VisitComma(expr); | 
| + case Token::OR: return VisitAndOr(expr, false); | 
| 
 
Kevin Millikin (Chromium)
2011/05/31 11:46:28
Let's not pass the flag here, since we can just us
 
Sven Panne
2011/05/31 14:30:33
Done, same for HGraphBuilder.
 
 | 
| + case Token::AND: return VisitAndOr(expr, true); | 
| + default: return VisitCommon(expr); | 
| + } | 
| +} | 
| + | 
| + | 
| +void FullCodeGenerator::VisitCommon(BinaryOperation* expr) { | 
| Token::Value op = expr->op(); | 
| Expression* left = expr->left(); | 
| Expression* right = expr->right(); | 
| + OverwriteMode mode = | 
| + left->ResultOverwriteAllowed() | 
| + ? OVERWRITE_LEFT | 
| + : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE); | 
| - OverwriteMode mode = NO_OVERWRITE; | 
| - if (left->ResultOverwriteAllowed()) { | 
| - mode = OVERWRITE_LEFT; | 
| - } else if (right->ResultOverwriteAllowed()) { | 
| - mode = OVERWRITE_RIGHT; | 
| - } | 
| + VisitForStackValue(left); | 
| + VisitForAccumulatorValue(right); | 
| - switch (op) { | 
| - case Token::COMMA: | 
| - VisitForEffect(left); | 
| - if (context()->IsTest()) ForwardBailoutToChild(expr); | 
| - context()->HandleExpression(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: { | 
| - // Load both operands. | 
| - VisitForStackValue(left); | 
| - VisitForAccumulatorValue(right); | 
| - | 
| - SetSourcePosition(expr->position()); | 
| - if (ShouldInlineSmiCase(op)) { | 
| - EmitInlineSmiBinaryOp(expr, op, mode, left, right); | 
| - } else { | 
| - EmitBinaryOp(expr, op, mode); | 
| - } | 
| - break; | 
| - } | 
| - | 
| - default: | 
| - UNREACHABLE(); | 
| + SetSourcePosition(expr->position()); | 
| + if (ShouldInlineSmiCase(op)) { | 
| + EmitInlineSmiBinaryOp(expr, op, mode, left, right); | 
| + } else { | 
| + EmitBinaryOp(expr, op, mode); | 
| } | 
| } | 
| -void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { | 
| - Label eval_right, done; | 
| - | 
| - context()->EmitLogicalLeft(expr, &eval_right, &done); | 
| - | 
| - PrepareForBailoutForId(expr->RightId(), NO_REGISTERS); | 
| - __ bind(&eval_right); | 
| +void FullCodeGenerator::VisitComma(BinaryOperation* expr) { | 
| + VisitForEffect(expr->left()); | 
| if (context()->IsTest()) ForwardBailoutToChild(expr); | 
| - context()->HandleExpression(expr->right()); | 
| - | 
| - __ bind(&done); | 
| + VisitInSameContext(expr->right()); | 
| } | 
| -void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr, | 
| - Label* eval_right, | 
| - Label* done) const { | 
| - if (expr->op() == Token::OR) { | 
| - codegen()->VisitForControl(expr->left(), done, eval_right, eval_right); | 
| - } else { | 
| - ASSERT(expr->op() == Token::AND); | 
| - codegen()->VisitForControl(expr->left(), eval_right, done, eval_right); | 
| - } | 
| -} | 
| +void FullCodeGenerator::VisitAndOr(BinaryOperation* expr, bool is_logical_and) { | 
| + Expression* left = expr->left(); | 
| + Expression* right = expr->right(); | 
| + int rightId = expr->RightId(); | 
| 
 
Kevin Millikin (Chromium)
2011/05/31 11:46:28
right_id
 
Sven Panne
2011/05/31 14:30:33
Done.
 
 | 
| + Label done; | 
| + if (context()->IsTest()) { | 
| 
 
Kevin Millikin (Chromium)
2011/05/31 11:46:28
I did like having this code as virtual functions o
 
Sven Panne
2011/05/31 14:30:33
In principle I agree that the explicit IfFooContex
 
 | 
| + Label eval_right; | 
| + const TestContext* test = TestContext::cast(context()); | 
| + if (is_logical_and) { | 
| + VisitForControl(left, &eval_right, test->false_label(), &eval_right); | 
| + } else { | 
| + VisitForControl(left, test->true_label(), &eval_right, &eval_right); | 
| + } | 
| + PrepareForBailoutForId(rightId, NO_REGISTERS); | 
| + __ bind(&eval_right); | 
| + ForwardBailoutToChild(expr); | 
| -void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft( | 
| - BinaryOperation* expr, | 
| - Label* eval_right, | 
| - Label* done) const { | 
| - HandleExpression(expr->left()); | 
| - // We want the value in the accumulator for the test, and on the stack in case | 
| - // we need it. | 
| - __ push(result_register()); | 
| - Label discard, restore; | 
| - if (expr->op() == Token::OR) { | 
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 
| - codegen()->DoTest(&restore, &discard, &restore); | 
| - } else { | 
| - ASSERT(expr->op() == Token::AND); | 
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 
| - codegen()->DoTest(&discard, &restore, &restore); | 
| - } | 
| - __ bind(&restore); | 
| - __ pop(result_register()); | 
| - __ jmp(done); | 
| - __ bind(&discard); | 
| - __ Drop(1); | 
| -} | 
| + } else if (context()->IsAccumulatorValue()) { | 
| + VisitForAccumulatorValue(left); | 
| + // We want the value in the accumulator for the test, and on the stack in | 
| + // case we need it. | 
| + __ push(result_register()); | 
| + Label discard, restore; | 
| + PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 
| + if (is_logical_and) { | 
| + DoTest(&discard, &restore, &restore); | 
| + } else { | 
| + DoTest(&restore, &discard, &restore); | 
| + } | 
| + __ bind(&restore); | 
| + __ pop(result_register()); | 
| + __ jmp(&done); | 
| + __ bind(&discard); | 
| + __ Drop(1); | 
| + PrepareForBailoutForId(rightId, NO_REGISTERS); | 
| + } else if (context()->IsStackValue()) { | 
| + VisitForAccumulatorValue(left); | 
| + // We want the value in the accumulator for the test, and on the stack in | 
| + // case we need it. | 
| + __ push(result_register()); | 
| + Label discard; | 
| + PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 
| + if (is_logical_and) { | 
| + DoTest(&discard, &done, &discard); | 
| + } else { | 
| + DoTest(&done, &discard, &discard); | 
| + } | 
| + __ bind(&discard); | 
| + __ Drop(1); | 
| + PrepareForBailoutForId(rightId, NO_REGISTERS); | 
| -void FullCodeGenerator::StackValueContext::EmitLogicalLeft( | 
| - BinaryOperation* expr, | 
| - Label* eval_right, | 
| - Label* done) const { | 
| - codegen()->VisitForAccumulatorValue(expr->left()); | 
| - // We want the value in the accumulator for the test, and on the stack in case | 
| - // we need it. | 
| - __ push(result_register()); | 
| - Label discard; | 
| - if (expr->op() == Token::OR) { | 
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 
| - codegen()->DoTest(done, &discard, &discard); | 
| } else { | 
| - ASSERT(expr->op() == Token::AND); | 
| - codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 
| - codegen()->DoTest(&discard, done, &discard); | 
| + ASSERT(context()->IsEffect()); | 
| + Label eval_right; | 
| + if (is_logical_and) { | 
| + VisitForControl(left, &eval_right, &done, &eval_right); | 
| + } else { | 
| + VisitForControl(left, &done, &eval_right, &eval_right); | 
| + } | 
| + PrepareForBailoutForId(rightId, NO_REGISTERS); | 
| + __ bind(&eval_right); | 
| } | 
| - __ bind(&discard); | 
| - __ Drop(1); | 
| -} | 
| - | 
| -void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr, | 
| - Label* eval_right, | 
| - Label* done) const { | 
| - if (expr->op() == Token::OR) { | 
| - codegen()->VisitForControl(expr->left(), | 
| - true_label_, eval_right, eval_right); | 
| - } else { | 
| - ASSERT(expr->op() == Token::AND); | 
| - codegen()->VisitForControl(expr->left(), | 
| - eval_right, false_label_, eval_right); | 
| - } | 
| + VisitInSameContext(right); | 
| + __ bind(&done); | 
| } | 
| @@ -850,49 +817,26 @@ | 
| } | 
| -void FullCodeGenerator::EffectContext::HandleExpression( | 
| - Expression* expr) const { | 
| - codegen()->HandleInNonTestContext(expr, NO_REGISTERS); | 
| +void FullCodeGenerator::VisitInSameContext(Expression* expr) { | 
| + if (context()->IsTest()) { | 
| + ForwardBailoutStack stack(expr, forward_bailout_pending_); | 
| + ForwardBailoutStack* saved = forward_bailout_stack_; | 
| + forward_bailout_pending_ = NULL; | 
| + forward_bailout_stack_ = &stack; | 
| + AstVisitor::Visit(expr); | 
| 
 
Kevin Millikin (Chromium)
2011/05/31 11:46:28
This can just be Visit(expr), can't it?
 
Sven Panne
2011/05/31 14:30:33
Done.
 
 | 
| + forward_bailout_stack_ = saved; | 
| + } else { | 
| + ASSERT(forward_bailout_pending_ == NULL); | 
| + Visit(expr); | 
| + State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS; | 
| + PrepareForBailout(expr, state); | 
| + // Forwarding bailouts to children is a one shot operation. It should have | 
| + // been processed at this point. | 
| + ASSERT(forward_bailout_pending_ == NULL); | 
| + } | 
| } | 
| -void FullCodeGenerator::AccumulatorValueContext::HandleExpression( | 
| - Expression* expr) const { | 
| - codegen()->HandleInNonTestContext(expr, TOS_REG); | 
| -} | 
| - | 
| - | 
| -void FullCodeGenerator::StackValueContext::HandleExpression( | 
| - Expression* expr) const { | 
| - codegen()->HandleInNonTestContext(expr, NO_REGISTERS); | 
| -} | 
| - | 
| - | 
| -void FullCodeGenerator::TestContext::HandleExpression(Expression* expr) const { | 
| - codegen()->VisitInTestContext(expr); | 
| -} | 
| - | 
| - | 
| -void FullCodeGenerator::HandleInNonTestContext(Expression* expr, State state) { | 
| - ASSERT(forward_bailout_pending_ == NULL); | 
| - AstVisitor::Visit(expr); | 
| - PrepareForBailout(expr, state); | 
| - // Forwarding bailouts to children is a one shot operation. It | 
| - // should have been processed at this point. | 
| - ASSERT(forward_bailout_pending_ == NULL); | 
| -} | 
| - | 
| - | 
| -void FullCodeGenerator::VisitInTestContext(Expression* expr) { | 
| - ForwardBailoutStack stack(expr, forward_bailout_pending_); | 
| - ForwardBailoutStack* saved = forward_bailout_stack_; | 
| - forward_bailout_pending_ = NULL; | 
| - forward_bailout_stack_ = &stack; | 
| - AstVisitor::Visit(expr); | 
| - forward_bailout_stack_ = saved; | 
| -} | 
| - | 
| - | 
| void FullCodeGenerator::VisitBlock(Block* stmt) { | 
| Comment cmnt(masm_, "[ Block"); | 
| Breakable nested_statement(this, stmt); | 
| @@ -1287,7 +1231,7 @@ | 
| for_test->false_label(), | 
| NULL); | 
| } else { | 
| - context()->HandleExpression(expr->then_expression()); | 
| + VisitInSameContext(expr->then_expression()); | 
| __ jmp(&done); | 
| } | 
| @@ -1296,7 +1240,7 @@ | 
| if (context()->IsTest()) ForwardBailoutToChild(expr); | 
| SetExpressionPosition(expr->else_expression(), | 
| expr->else_expression_position()); | 
| - context()->HandleExpression(expr->else_expression()); | 
| + VisitInSameContext(expr->else_expression()); | 
| // If control flow falls through Visit, merge it with true case here. | 
| if (!context()->IsTest()) { | 
| __ bind(&done); |