Index: src/ia32/codegen-ia32.cc |
=================================================================== |
--- src/ia32/codegen-ia32.cc (revision 3045) |
+++ src/ia32/codegen-ia32.cc (working copy) |
@@ -2698,288 +2698,331 @@ |
} |
-void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
+void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { |
ASSERT(!in_spilled_code()); |
- Comment cmnt(masm_, "[ LoopStatement"); |
+ Comment cmnt(masm_, "[ DoWhileStatement"); |
CodeForStatementPosition(node); |
node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ JumpTarget body(JumpTarget::BIDIRECTIONAL); |
+ IncrementLoopNesting(); |
- // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a |
- // known result for the test expression, with no side effects. |
- enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
- if (node->cond() == NULL) { |
- ASSERT(node->type() == LoopStatement::FOR_LOOP); |
- info = ALWAYS_TRUE; |
- } else { |
- Literal* lit = node->cond()->AsLiteral(); |
- if (lit != NULL) { |
- if (lit->IsTrue()) { |
- info = ALWAYS_TRUE; |
- } else if (lit->IsFalse()) { |
- info = ALWAYS_FALSE; |
+ ConditionAnalysis info = AnalyzeCondition(node->cond()); |
+ // Label the top of the loop for the backward jump if necessary. |
+ switch (info) { |
+ case ALWAYS_TRUE: |
+ // Use the continue target. |
+ node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
+ node->continue_target()->Bind(); |
+ break; |
+ case ALWAYS_FALSE: |
+ // No need to label it. |
+ node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ break; |
+ case DONT_KNOW: |
+ // Continue is the test, so use the backward body target. |
+ node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ body.Bind(); |
+ break; |
+ } |
+ |
+ CheckStack(); // TODO(1222600): ignore if body contains calls. |
+ Visit(node->body()); |
+ |
+ // Compile the test. |
+ switch (info) { |
+ case ALWAYS_TRUE: |
+ // If control flow can fall off the end of the body, jump back to |
+ // the top and bind the break target at the exit. |
+ if (has_valid_frame()) { |
+ node->continue_target()->Jump(); |
} |
- } |
+ if (node->break_target()->is_linked()) { |
+ node->break_target()->Bind(); |
+ } |
+ break; |
+ case ALWAYS_FALSE: |
+ // We may have had continues or breaks in the body. |
+ if (node->continue_target()->is_linked()) { |
+ node->continue_target()->Bind(); |
+ } |
+ if (node->break_target()->is_linked()) { |
+ node->break_target()->Bind(); |
+ } |
+ break; |
+ case DONT_KNOW: |
+ // We have to compile the test expression if it can be reached by |
+ // control flow falling out of the body or via continue. |
+ if (node->continue_target()->is_linked()) { |
+ node->continue_target()->Bind(); |
+ } |
+ if (has_valid_frame()) { |
+ ControlDestination dest(&body, node->break_target(), false); |
+ LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
+ } |
+ if (node->break_target()->is_linked()) { |
+ node->break_target()->Bind(); |
+ } |
+ break; |
} |
- switch (node->type()) { |
- case LoopStatement::DO_LOOP: { |
- JumpTarget body(JumpTarget::BIDIRECTIONAL); |
- IncrementLoopNesting(); |
+ DecrementLoopNesting(); |
+} |
- // Label the top of the loop for the backward jump if necessary. |
- if (info == ALWAYS_TRUE) { |
- // Use the continue target. |
+ |
+void CodeGenerator::VisitWhileStatement(WhileStatement* node) { |
+ ASSERT(!in_spilled_code()); |
+ Comment cmnt(masm_, "[ WhileStatement"); |
+ CodeForStatementPosition(node); |
+ |
+ // If the condition is always false and has no side effects, we do not |
+ // need to compile anything. |
+ ConditionAnalysis info = AnalyzeCondition(node->cond()); |
+ if (info == ALWAYS_FALSE) return; |
+ |
+ // Do not duplicate conditions that may have function literal |
+ // subexpressions. This can cause us to compile the function literal |
+ // twice. |
+ bool test_at_bottom = !node->may_have_function_literal(); |
+ node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ IncrementLoopNesting(); |
+ JumpTarget body; |
+ if (test_at_bottom) { |
+ body.set_direction(JumpTarget::BIDIRECTIONAL); |
+ } |
+ |
+ // Based on the condition analysis, compile the test as necessary. |
+ switch (info) { |
+ case ALWAYS_TRUE: |
+ // We will not compile the test expression. Label the top of the |
+ // loop with the continue target. |
+ node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
+ node->continue_target()->Bind(); |
+ break; |
+ case DONT_KNOW: { |
+ if (test_at_bottom) { |
+ // Continue is the test at the bottom, no need to label the test |
+ // at the top. The body is a backward target. |
+ node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ } else { |
+ // Label the test at the top as the continue target. The body |
+ // is a forward-only target. |
node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
node->continue_target()->Bind(); |
- } else if (info == ALWAYS_FALSE) { |
- // No need to label it. |
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
- } else { |
- // Continue is the test, so use the backward body target. |
- ASSERT(info == DONT_KNOW); |
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
- body.Bind(); |
} |
+ // Compile the test with the body as the true target and preferred |
+ // fall-through and with the break target as the false target. |
+ ControlDestination dest(&body, node->break_target(), true); |
+ LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
- CheckStack(); // TODO(1222600): ignore if body contains calls. |
- Visit(node->body()); |
- |
- // Compile the test. |
- if (info == ALWAYS_TRUE) { |
- // If control flow can fall off the end of the body, jump back |
- // to the top and bind the break target at the exit. |
- if (has_valid_frame()) { |
- node->continue_target()->Jump(); |
+ if (dest.false_was_fall_through()) { |
+ // If we got the break target as fall-through, the test may have |
+ // been unconditionally false (if there are no jumps to the |
+ // body). |
+ if (!body.is_linked()) { |
+ DecrementLoopNesting(); |
+ return; |
} |
- if (node->break_target()->is_linked()) { |
- node->break_target()->Bind(); |
- } |
- } else if (info == ALWAYS_FALSE) { |
- // We may have had continues or breaks in the body. |
- if (node->continue_target()->is_linked()) { |
- node->continue_target()->Bind(); |
- } |
- if (node->break_target()->is_linked()) { |
- node->break_target()->Bind(); |
- } |
+ // Otherwise, jump around the body on the fall through and then |
+ // bind the body target. |
+ node->break_target()->Unuse(); |
+ node->break_target()->Jump(); |
+ body.Bind(); |
+ } |
+ break; |
+ } |
+ case ALWAYS_FALSE: |
+ UNREACHABLE(); |
+ break; |
+ } |
- } else { |
- ASSERT(info == DONT_KNOW); |
- // We have to compile the test expression if it can be reached by |
- // control flow falling out of the body or via continue. |
+ CheckStack(); // TODO(1222600): ignore if body contains calls. |
+ Visit(node->body()); |
+ |
+ // Based on the condition analysis, compile the backward jump as |
+ // necessary. |
+ switch (info) { |
+ case ALWAYS_TRUE: |
+ // The loop body has been labeled with the continue target. |
+ if (has_valid_frame()) { |
+ node->continue_target()->Jump(); |
+ } |
+ break; |
+ case DONT_KNOW: |
+ if (test_at_bottom) { |
+ // If we have chosen to recompile the test at the bottom, then |
+ // it is the continue target. |
if (node->continue_target()->is_linked()) { |
node->continue_target()->Bind(); |
} |
if (has_valid_frame()) { |
+ // The break target is the fall-through (body is a backward |
+ // jump from here and thus an invalid fall-through). |
ControlDestination dest(&body, node->break_target(), false); |
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
} |
- if (node->break_target()->is_linked()) { |
- node->break_target()->Bind(); |
+ } else { |
+ // If we have chosen not to recompile the test at the bottom, |
+ // jump back to the one at the top. |
+ if (has_valid_frame()) { |
+ node->continue_target()->Jump(); |
} |
} |
break; |
- } |
+ case ALWAYS_FALSE: |
+ UNREACHABLE(); |
+ break; |
+ } |
- case LoopStatement::WHILE_LOOP: { |
- // Do not duplicate conditions that may have function literal |
- // subexpressions. This can cause us to compile the function |
- // literal twice. |
- bool test_at_bottom = !node->may_have_function_literal(); |
+ // The break target may be already bound (by the condition), or there |
+ // may not be a valid frame. Bind it only if needed. |
+ if (node->break_target()->is_linked()) { |
+ node->break_target()->Bind(); |
+ } |
+ DecrementLoopNesting(); |
+} |
- IncrementLoopNesting(); |
- // If the condition is always false and has no side effects, we |
- // do not need to compile anything. |
- if (info == ALWAYS_FALSE) break; |
+void CodeGenerator::VisitForStatement(ForStatement* node) { |
+ ASSERT(!in_spilled_code()); |
+ Comment cmnt(masm_, "[ ForStatement"); |
+ CodeForStatementPosition(node); |
- JumpTarget body; |
- if (test_at_bottom) { |
- body.set_direction(JumpTarget::BIDIRECTIONAL); |
- } |
+ // Compile the init expression if present. |
+ if (node->init() != NULL) { |
+ Visit(node->init()); |
+ } |
- // Based on the condition analysis, compile the test as necessary. |
- if (info == ALWAYS_TRUE) { |
- // We will not compile the test expression. Label the top of |
- // the loop with the continue target. |
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
- node->continue_target()->Bind(); |
- } else { |
- ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
- if (test_at_bottom) { |
- // Continue is the test at the bottom, no need to label the |
- // test at the top. The body is a backward target. |
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
- } else { |
- // Label the test at the top as the continue target. The |
- // body is a forward-only target. |
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
- node->continue_target()->Bind(); |
- } |
- // Compile the test with the body as the true target and |
- // preferred fall-through and with the break target as the |
- // false target. |
- ControlDestination dest(&body, node->break_target(), true); |
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
+ // If the condition is always false and has no side effects, we do not |
+ // need to compile anything else. |
+ ConditionAnalysis info = AnalyzeCondition(node->cond()); |
+ if (info == ALWAYS_FALSE) return; |
- if (dest.false_was_fall_through()) { |
- // If we got the break target as fall-through, the test may |
- // have been unconditionally false (if there are no jumps to |
- // the body). |
- if (!body.is_linked()) break; |
+ // Do not duplicate conditions that may have function literal |
+ // subexpressions. This can cause us to compile the function literal |
+ // twice. |
+ bool test_at_bottom = !node->may_have_function_literal(); |
+ node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ IncrementLoopNesting(); |
- // Otherwise, jump around the body on the fall through and |
- // then bind the body target. |
- node->break_target()->Unuse(); |
- node->break_target()->Jump(); |
- body.Bind(); |
- } |
- } |
+ // Target for backward edge if no test at the bottom, otherwise |
+ // unused. |
+ JumpTarget loop(JumpTarget::BIDIRECTIONAL); |
- CheckStack(); // TODO(1222600): ignore if body contains calls. |
- Visit(node->body()); |
+ // Target for backward edge if there is a test at the bottom, |
+ // otherwise used as target for test at the top. |
+ JumpTarget body; |
+ if (test_at_bottom) { |
+ body.set_direction(JumpTarget::BIDIRECTIONAL); |
+ } |
- // Based on the condition analysis, compile the backward jump as |
- // necessary. |
- if (info == ALWAYS_TRUE) { |
- // The loop body has been labeled with the continue target. |
- if (has_valid_frame()) { |
- node->continue_target()->Jump(); |
- } |
+ // Based on the condition analysis, compile the test as necessary. |
+ switch (info) { |
+ case ALWAYS_TRUE: |
+ // We will not compile the test expression. Label the top of the |
+ // loop. |
+ if (node->next() == NULL) { |
+ // Use the continue target if there is no update expression. |
+ node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
+ node->continue_target()->Bind(); |
} else { |
- ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
- if (test_at_bottom) { |
- // If we have chosen to recompile the test at the bottom, |
- // then it is the continue target. |
- if (node->continue_target()->is_linked()) { |
- node->continue_target()->Bind(); |
- } |
- if (has_valid_frame()) { |
- // The break target is the fall-through (body is a backward |
- // jump from here and thus an invalid fall-through). |
- ControlDestination dest(&body, node->break_target(), false); |
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
- } |
- } else { |
- // If we have chosen not to recompile the test at the |
- // bottom, jump back to the one at the top. |
- if (has_valid_frame()) { |
- node->continue_target()->Jump(); |
- } |
- } |
+ // Otherwise use the backward loop target. |
+ node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ loop.Bind(); |
} |
+ break; |
+ case DONT_KNOW: { |
+ if (test_at_bottom) { |
+ // Continue is either the update expression or the test at the |
+ // bottom, no need to label the test at the top. |
+ node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ } else if (node->next() == NULL) { |
+ // We are not recompiling the test at the bottom and there is no |
+ // update expression. |
+ node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
+ node->continue_target()->Bind(); |
+ } else { |
+ // We are not recompiling the test at the bottom and there is an |
+ // update expression. |
+ node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
+ loop.Bind(); |
+ } |
+ // Compile the test with the body as the true target and preferred |
+ // fall-through and with the break target as the false target. |
+ ControlDestination dest(&body, node->break_target(), true); |
+ LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
- // The break target may be already bound (by the condition), or |
- // there may not be a valid frame. Bind it only if needed. |
- if (node->break_target()->is_linked()) { |
- node->break_target()->Bind(); |
+ if (dest.false_was_fall_through()) { |
+ // If we got the break target as fall-through, the test may have |
+ // been unconditionally false (if there are no jumps to the |
+ // body). |
+ if (!body.is_linked()) { |
+ DecrementLoopNesting(); |
+ return; |
+ } |
+ |
+ // Otherwise, jump around the body on the fall through and then |
+ // bind the body target. |
+ node->break_target()->Unuse(); |
+ node->break_target()->Jump(); |
+ body.Bind(); |
} |
break; |
} |
+ case ALWAYS_FALSE: |
+ UNREACHABLE(); |
+ break; |
+ } |
- case LoopStatement::FOR_LOOP: { |
- // Do not duplicate conditions that may have function literal |
- // subexpressions. This can cause us to compile the function |
- // literal twice. |
- bool test_at_bottom = !node->may_have_function_literal(); |
+ CheckStack(); // TODO(1222600): ignore if body contains calls. |
+ Visit(node->body()); |
- // Compile the init expression if present. |
- if (node->init() != NULL) { |
- Visit(node->init()); |
- } |
+ // If there is an update expression, compile it if necessary. |
+ if (node->next() != NULL) { |
+ if (node->continue_target()->is_linked()) { |
+ node->continue_target()->Bind(); |
+ } |
- IncrementLoopNesting(); |
+ // Control can reach the update by falling out of the body or by a |
+ // continue. |
+ if (has_valid_frame()) { |
+ // Record the source position of the statement as this code which |
+ // is after the code for the body actually belongs to the loop |
+ // statement and not the body. |
+ CodeForStatementPosition(node); |
+ Visit(node->next()); |
+ } |
+ } |
- // If the condition is always false and has no side effects, we |
- // do not need to compile anything else. |
- if (info == ALWAYS_FALSE) break; |
- |
- // Target for backward edge if no test at the bottom, otherwise |
- // unused. |
- JumpTarget loop(JumpTarget::BIDIRECTIONAL); |
- |
- // Target for backward edge if there is a test at the bottom, |
- // otherwise used as target for test at the top. |
- JumpTarget body; |
- if (test_at_bottom) { |
- body.set_direction(JumpTarget::BIDIRECTIONAL); |
- } |
- |
- // Based on the condition analysis, compile the test as necessary. |
- if (info == ALWAYS_TRUE) { |
- // We will not compile the test expression. Label the top of |
- // the loop. |
+ // Based on the condition analysis, compile the backward jump as |
+ // necessary. |
+ switch (info) { |
+ case ALWAYS_TRUE: |
+ if (has_valid_frame()) { |
if (node->next() == NULL) { |
- // Use the continue target if there is no update expression. |
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
- node->continue_target()->Bind(); |
+ node->continue_target()->Jump(); |
} else { |
- // Otherwise use the backward loop target. |
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
- loop.Bind(); |
+ loop.Jump(); |
} |
- } else { |
- ASSERT(info == DONT_KNOW); |
- if (test_at_bottom) { |
- // Continue is either the update expression or the test at |
- // the bottom, no need to label the test at the top. |
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
- } else if (node->next() == NULL) { |
- // We are not recompiling the test at the bottom and there |
- // is no update expression. |
- node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
- node->continue_target()->Bind(); |
- } else { |
- // We are not recompiling the test at the bottom and there |
- // is an update expression. |
- node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
- loop.Bind(); |
- } |
- |
- // Compile the test with the body as the true target and |
- // preferred fall-through and with the break target as the |
- // false target. |
- ControlDestination dest(&body, node->break_target(), true); |
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
- |
- if (dest.false_was_fall_through()) { |
- // If we got the break target as fall-through, the test may |
- // have been unconditionally false (if there are no jumps to |
- // the body). |
- if (!body.is_linked()) break; |
- |
- // Otherwise, jump around the body on the fall through and |
- // then bind the body target. |
- node->break_target()->Unuse(); |
- node->break_target()->Jump(); |
- body.Bind(); |
- } |
} |
- |
- CheckStack(); // TODO(1222600): ignore if body contains calls. |
- Visit(node->body()); |
- |
- // If there is an update expression, compile it if necessary. |
- if (node->next() != NULL) { |
+ case DONT_KNOW: |
+ if (test_at_bottom) { |
if (node->continue_target()->is_linked()) { |
+ // We can have dangling jumps to the continue target if there |
+ // was no update expression. |
node->continue_target()->Bind(); |
} |
- |
- // Control can reach the update by falling out of the body or |
- // by a continue. |
+ // Control can reach the test at the bottom by falling out of |
+ // the body, by a continue in the body, or from the update |
+ // expression. |
if (has_valid_frame()) { |
- // Record the source position of the statement as this code |
- // which is after the code for the body actually belongs to |
- // the loop statement and not the body. |
- CodeForStatementPosition(node); |
- Visit(node->next()); |
+ // The break target is the fall-through (body is a backward |
+ // jump from here). |
+ ControlDestination dest(&body, node->break_target(), false); |
+ LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
} |
- } |
- |
- // Based on the condition analysis, compile the backward jump as |
- // necessary. |
- if (info == ALWAYS_TRUE) { |
+ } else { |
+ // Otherwise, jump back to the test at the top. |
if (has_valid_frame()) { |
if (node->next() == NULL) { |
node->continue_target()->Jump(); |
@@ -2987,47 +3030,18 @@ |
loop.Jump(); |
} |
} |
- } else { |
- ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
- if (test_at_bottom) { |
- if (node->continue_target()->is_linked()) { |
- // We can have dangling jumps to the continue target if |
- // there was no update expression. |
- node->continue_target()->Bind(); |
- } |
- // Control can reach the test at the bottom by falling out |
- // of the body, by a continue in the body, or from the |
- // update expression. |
- if (has_valid_frame()) { |
- // The break target is the fall-through (body is a |
- // backward jump from here). |
- ControlDestination dest(&body, node->break_target(), false); |
- LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
- } |
- } else { |
- // Otherwise, jump back to the test at the top. |
- if (has_valid_frame()) { |
- if (node->next() == NULL) { |
- node->continue_target()->Jump(); |
- } else { |
- loop.Jump(); |
- } |
- } |
- } |
} |
- |
- // The break target may be already bound (by the condition), or |
- // there may not be a valid frame. Bind it only if needed. |
- if (node->break_target()->is_linked()) { |
- node->break_target()->Bind(); |
- } |
+ case ALWAYS_FALSE: |
+ UNREACHABLE(); |
break; |
- } |
} |
+ // The break target may be already bound (by the condition), or |
+ // there may not be a valid frame. Bind it only if needed. |
+ if (node->break_target()->is_linked()) { |
+ node->break_target()->Bind(); |
+ } |
DecrementLoopNesting(); |
- node->continue_target()->Unuse(); |
- node->break_target()->Unuse(); |
} |
@@ -3221,10 +3235,10 @@ |
} |
-void CodeGenerator::VisitTryCatch(TryCatch* node) { |
+void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { |
ASSERT(!in_spilled_code()); |
VirtualFrame::SpilledScope spilled_scope; |
- Comment cmnt(masm_, "[ TryCatch"); |
+ Comment cmnt(masm_, "[ TryCatchStatement"); |
CodeForStatementPosition(node); |
JumpTarget try_block; |
@@ -3357,10 +3371,10 @@ |
} |
-void CodeGenerator::VisitTryFinally(TryFinally* node) { |
+void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) { |
ASSERT(!in_spilled_code()); |
VirtualFrame::SpilledScope spilled_scope; |
- Comment cmnt(masm_, "[ TryFinally"); |
+ Comment cmnt(masm_, "[ TryFinallyStatement"); |
CodeForStatementPosition(node); |
// State: Used to keep track of reason for entering the finally |