Index: src/full-codegen.cc |
=================================================================== |
--- src/full-codegen.cc (revision 5450) |
+++ src/full-codegen.cc (working copy) |
@@ -336,33 +336,123 @@ |
} |
-void FullCodeGenerator::PrepareTest(Label* materialize_true, |
- Label* materialize_false, |
- Label** if_true, |
- Label** if_false, |
- Label** fall_through) { |
- switch (context_) { |
- case Expression::kUninitialized: |
- UNREACHABLE(); |
- break; |
- case Expression::kEffect: |
- // In an effect context, the true and the false case branch to the |
- // same label. |
- *if_true = *if_false = *fall_through = materialize_true; |
- break; |
- case Expression::kValue: |
- *if_true = *fall_through = materialize_true; |
- *if_false = materialize_false; |
- break; |
- case Expression::kTest: |
- *if_true = true_label_; |
- *if_false = false_label_; |
- *fall_through = fall_through_; |
- break; |
- } |
+void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
+ Register reg) const { |
+ ASSERT(count > 0); |
+ __ Drop(count); |
} |
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug( |
+ int count, |
+ Register reg) const { |
+ ASSERT(count > 0); |
+ __ Drop(count); |
+ __ Move(result_register(), reg); |
+} |
+ |
+ |
+void FullCodeGenerator::TestContext::DropAndPlug(int count, |
+ Register reg) const { |
+ ASSERT(count > 0); |
+ // For simplicity we always test the accumulator register. |
+ __ Drop(count); |
+ __ Move(result_register(), reg); |
+ codegen()->DoTest(true_label_, false_label_, fall_through_); |
+} |
+ |
+ |
+void FullCodeGenerator::EffectContext::Plug(Register reg) const { |
+ // Nothing to do. |
+} |
+ |
+ |
+void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { |
+ // Move value into place. |
+ __ Move(result_register(), reg); |
+} |
+ |
+ |
+void FullCodeGenerator::StackValueContext::Plug(Register reg) const { |
+ // Move value into place. |
+ __ push(reg); |
+} |
+ |
+ |
+void FullCodeGenerator::TestContext::Plug(Register reg) const { |
+ // For simplicity we always test the accumulator register. |
+ __ Move(result_register(), reg); |
+ codegen()->DoTest(true_label_, false_label_, fall_through_); |
+} |
+ |
+ |
+void FullCodeGenerator::EffectContext::PlugTOS() const { |
+ __ Drop(1); |
+} |
+ |
+ |
+void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { |
+ __ pop(result_register()); |
+} |
+ |
+ |
+void FullCodeGenerator::StackValueContext::PlugTOS() const { |
+} |
+ |
+ |
+void FullCodeGenerator::TestContext::PlugTOS() const { |
+ // For simplicity we always test the accumulator register. |
+ __ pop(result_register()); |
+ codegen()->DoTest(true_label_, false_label_, fall_through_); |
+} |
+ |
+ |
+void FullCodeGenerator::EffectContext::PrepareTest( |
+ Label* materialize_true, |
+ Label* materialize_false, |
+ Label** if_true, |
+ Label** if_false, |
+ Label** fall_through) const { |
+ // In an effect context, the true and the false case branch to the |
+ // same label. |
+ *if_true = *if_false = *fall_through = materialize_true; |
+} |
+ |
+ |
+void FullCodeGenerator::AccumulatorValueContext::PrepareTest( |
+ Label* materialize_true, |
+ Label* materialize_false, |
+ Label** if_true, |
+ Label** if_false, |
+ Label** fall_through) const { |
+ *if_true = *fall_through = materialize_true; |
+ *if_false = materialize_false; |
+} |
+ |
+ |
+void FullCodeGenerator::StackValueContext::PrepareTest( |
+ Label* materialize_true, |
+ Label* materialize_false, |
+ Label** if_true, |
+ Label** if_false, |
+ Label** fall_through) const { |
+ *if_true = *fall_through = materialize_true; |
+ *if_false = materialize_false; |
+} |
+ |
+ |
+void FullCodeGenerator::TestContext::PrepareTest( |
+ Label* materialize_true, |
+ Label* materialize_false, |
+ Label** if_true, |
+ Label** if_false, |
+ Label** fall_through) const { |
+ *if_true = true_label_; |
+ *if_false = false_label_; |
+ *fall_through = fall_through_; |
+} |
+ |
+ |
void FullCodeGenerator::VisitDeclarations( |
ZoneList<Declaration*>* declarations) { |
int length = declarations->length(); |
@@ -562,20 +652,20 @@ |
// Load only the operands that we need to materialize. |
if (constant == kNoConstants) { |
- VisitForValue(left, kStack); |
- VisitForValue(right, kAccumulator); |
+ VisitForStackValue(left); |
+ VisitForAccumulatorValue(right); |
} else if (constant == kRightConstant) { |
- VisitForValue(left, kAccumulator); |
+ VisitForAccumulatorValue(left); |
} else { |
ASSERT(constant == kLeftConstant); |
- VisitForValue(right, kAccumulator); |
+ VisitForAccumulatorValue(right); |
} |
SetSourcePosition(expr->position()); |
if (ShouldInlineSmiCase(op)) { |
- EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant); |
+ EmitInlineSmiBinaryOp(expr, op, mode, left, right, constant); |
} else { |
- EmitBinaryOp(op, context_, mode); |
+ EmitBinaryOp(op, mode); |
} |
break; |
} |
@@ -589,39 +679,7 @@ |
void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) { |
Label eval_right, done; |
- // Set up the appropriate context for the left subexpression based |
- // on the operation and our own context. Initially assume we can |
- // inherit both true and false labels from our context. |
- if (expr->op() == Token::OR) { |
- switch (context_) { |
- case Expression::kUninitialized: |
- UNREACHABLE(); |
- case Expression::kEffect: |
- VisitForControl(expr->left(), &done, &eval_right, &eval_right); |
- break; |
- case Expression::kValue: |
- VisitLogicalForValue(expr->left(), expr->op(), location_, &done); |
- break; |
- case Expression::kTest: |
- VisitForControl(expr->left(), true_label_, &eval_right, &eval_right); |
- break; |
- } |
- } else { |
- ASSERT_EQ(Token::AND, expr->op()); |
- switch (context_) { |
- case Expression::kUninitialized: |
- UNREACHABLE(); |
- case Expression::kEffect: |
- VisitForControl(expr->left(), &eval_right, &done, &eval_right); |
- break; |
- case Expression::kValue: |
- VisitLogicalForValue(expr->left(), expr->op(), location_, &done); |
- break; |
- case Expression::kTest: |
- VisitForControl(expr->left(), &eval_right, false_label_, &eval_right); |
- break; |
- } |
- } |
+ context()->EmitLogicalLeft(expr, &eval_right, &done); |
__ bind(&eval_right); |
Visit(expr->right()); |
@@ -630,43 +688,75 @@ |
} |
-void FullCodeGenerator::VisitLogicalForValue(Expression* expr, |
- Token::Value op, |
- Location where, |
- Label* done) { |
- ASSERT(op == Token::AND || op == Token::OR); |
- VisitForValue(expr, kAccumulator); |
+// Set up the appropriate context for the left subexpression based |
+// on the operation and our own context. Initially assume we can |
+// inherit both true and false labels from our context. |
+ |
+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::AccumulatorValueContext::EmitLogicalLeft( |
+ BinaryOperation* expr, |
+ Label* eval_right, |
+ Label* done) const { |
+ codegen()->Visit(expr->left()); |
__ push(result_register()); |
+ Label discard, restore; |
+ if (expr->op() == Token::OR) { |
+ codegen()->DoTest(&restore, &discard, &restore); |
+ } else { |
+ ASSERT(expr->op() == Token::AND); |
+ codegen()->DoTest(&discard, &restore, &restore); |
+ } |
+ __ bind(&restore); |
+ __ pop(result_register()); |
+ __ jmp(done); |
+ __ bind(&discard); |
+ __ Drop(1); |
+} |
+ |
+void FullCodeGenerator::StackValueContext::EmitLogicalLeft( |
+ BinaryOperation* expr, |
+ Label* eval_right, |
+ Label* done) const { |
+ codegen()->VisitForAccumulatorValue(expr->left()); |
+ __ push(result_register()); |
Label discard; |
- switch (where) { |
- case kAccumulator: { |
- Label restore; |
- if (op == Token::OR) { |
- DoTest(&restore, &discard, &restore); |
- } else { |
- DoTest(&discard, &restore, &restore); |
- } |
- __ bind(&restore); |
- __ pop(result_register()); |
- __ jmp(done); |
- break; |
- } |
- case kStack: { |
- if (op == Token::OR) { |
- DoTest(done, &discard, &discard); |
- } else { |
- DoTest(&discard, done, &discard); |
- } |
- break; |
- } |
+ if (expr->op() == Token::OR) { |
+ codegen()->DoTest(done, &discard, &discard); |
+ } else { |
+ ASSERT(expr->op() == Token::AND); |
+ codegen()->DoTest(&discard, done, &discard); |
} |
- |
__ 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); |
+ } |
+} |
+ |
+ |
void FullCodeGenerator::VisitBlock(Block* stmt) { |
Comment cmnt(masm_, "[ Block"); |
Breakable nested_statement(this, stmt); |
@@ -747,7 +837,7 @@ |
Comment cmnt(masm_, "[ ReturnStatement"); |
SetStatementPosition(stmt); |
Expression* expr = stmt->expression(); |
- VisitForValue(expr, kAccumulator); |
+ VisitForAccumulatorValue(expr); |
// Exit all nested statements. |
NestedStatement* current = nesting_stack_; |
@@ -766,7 +856,7 @@ |
Comment cmnt(masm_, "[ WithEnterStatement"); |
SetStatementPosition(stmt); |
- VisitForValue(stmt->expression(), kStack); |
+ VisitForStackValue(stmt->expression()); |
if (stmt->is_catch_block()) { |
__ CallRuntime(Runtime::kPushCatchContext, 1); |
} else { |
@@ -1047,7 +1137,7 @@ |
expr->then_expression_position()); |
Visit(expr->then_expression()); |
// If control flow falls through Visit, jump to done. |
- if (context_ == Expression::kEffect || context_ == Expression::kValue) { |
+ if (!context()->IsTest()) { |
__ jmp(&done); |
} |
@@ -1056,7 +1146,7 @@ |
expr->else_expression_position()); |
Visit(expr->else_expression()); |
// If control flow falls through Visit, merge it with true case here. |
- if (context_ == Expression::kEffect || context_ == Expression::kValue) { |
+ if (!context()->IsTest()) { |
__ bind(&done); |
} |
} |
@@ -1070,7 +1160,7 @@ |
void FullCodeGenerator::VisitLiteral(Literal* expr) { |
Comment cmnt(masm_, "[ Literal"); |
- Apply(context_, expr); |
+ context()->Plug(expr->handle()); |
} |
@@ -1096,17 +1186,17 @@ |
// Call runtime routine to allocate the catch extension object and |
// assign the exception value to the catch variable. |
Comment cmnt(masm_, "[ CatchExtensionObject"); |
- VisitForValue(expr->key(), kStack); |
- VisitForValue(expr->value(), kStack); |
+ VisitForStackValue(expr->key()); |
+ VisitForStackValue(expr->value()); |
// Create catch extension object. |
__ CallRuntime(Runtime::kCreateCatchExtensionObject, 2); |
- Apply(context_, result_register()); |
+ context()->Plug(result_register()); |
} |
void FullCodeGenerator::VisitThrow(Throw* expr) { |
Comment cmnt(masm_, "[ Throw"); |
- VisitForValue(expr->exception(), kStack); |
+ VisitForStackValue(expr->exception()); |
__ CallRuntime(Runtime::kThrow, 1); |
// Never returns here. |
} |
@@ -1136,9 +1226,9 @@ |
void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) { |
ASSERT(args->length() == 1); |
- VisitForValue(args->at(0), kStack); |
+ VisitForStackValue(args->at(0)); |
__ CallRuntime(Runtime::kRegExpCloneResult, 1); |
- Apply(context_, result_register()); |
+ context()->Plug(result_register()); |
} |
#undef __ |