Index: src/codegen-ia32.cc |
=================================================================== |
--- src/codegen-ia32.cc (revision 1450) |
+++ src/codegen-ia32.cc (working copy) |
@@ -2174,15 +2174,16 @@ |
JumpTarget body(this, JumpTarget::BIDIRECTIONAL); |
IncrementLoopNesting(); |
- // Label the top of the loop for the backward CFG edge. If the test |
- // is always true we can use the continue target, and if the test is |
- // always false there is no need. |
+ // Label the top of the loop for the backward jump if necessary. |
if (info == ALWAYS_TRUE) { |
+ // Use the continue target. |
node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
node->continue_target()->Bind(); |
} else if (info == ALWAYS_FALSE) { |
+ // No need to label it. |
node->continue_target()->Initialize(this); |
} else { |
+ // Continue is the test, so use the backward body target. |
ASSERT(info == DONT_KNOW); |
node->continue_target()->Initialize(this); |
body.Bind(); |
@@ -2193,8 +2194,8 @@ |
// 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 as the exit. |
+ // 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(); |
} |
@@ -2230,15 +2231,19 @@ |
} |
case LoopStatement::WHILE_LOOP: { |
- JumpTarget body(this, JumpTarget::BIDIRECTIONAL); |
+ // TODO(260): This flag controls whether to duplicate the test |
+ // at the bottom of the loop. Replace it with a better |
+ // indication of when it is safe to do so. |
+ static const bool test_at_bottom = false; |
+ |
+ JumpTarget body; // Uninitialized. |
IncrementLoopNesting(); |
// If the condition is always false and has no side effects, we |
// do not need to compile anything. |
if (info == ALWAYS_FALSE) break; |
- // Based on the condition analysis, compile the test if |
- // necessary and label the body if necessary. |
+ // 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. |
@@ -2246,7 +2251,18 @@ |
node->continue_target()->Bind(); |
} else { |
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
- node->continue_target()->Initialize(this); |
+ 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()->Initialize(this); |
+ body.Initialize(this, JumpTarget::BIDIRECTIONAL); |
+ } else { |
+ // Label the test at the top as the continue target. The |
+ // body is a forward-only target. |
+ node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
+ node->continue_target()->Bind(); |
+ body.Initialize(this); |
+ } |
// Compile the test with the body as the true target and |
// preferred fall-through and with the break target as the |
// false target. |
@@ -2254,9 +2270,9 @@ |
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
if (dest.false_was_fall_through()) { |
- // If we don't have dangling jumps to the body, the test is |
- // unconditionally false and we do not need to compile the |
- // body. |
+ // 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 |
@@ -2267,31 +2283,37 @@ |
} |
} |
- // The (stack check at the start of the) body was labeled. |
- // Compile it. |
CheckStack(); // TODO(1222600): ignore if body contains calls. |
Visit(node->body()); |
- // Compile the test if necessary and jump back. |
+ // Based on the condition analysis, compile the backward jump as |
+ // necessary. |
if (info == ALWAYS_TRUE) { |
- // The body has been labeled with the continue target. |
+ // The loop body has been labeled with the continue target. |
if (has_valid_frame()) { |
node->continue_target()->Jump(); |
} |
} else { |
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
- if (node->continue_target()->is_linked()) { |
- node->continue_target()->Bind(); |
+ 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(); |
+ } |
} |
- |
- // If control can reach the bottom by falling off the body or |
- // a continue in the body, (re)compile the test at the bottom. |
- 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); |
- } |
} |
// The break target may be already bound (by the condition), or |
@@ -2303,8 +2325,14 @@ |
} |
case LoopStatement::FOR_LOOP: { |
- JumpTarget body(this, JumpTarget::BIDIRECTIONAL); |
+ // TODO(260): This flag controls whether to duplicate the test |
+ // at the bottom of the loop. Replace it with a better |
+ // indication of when it is safe to do so. |
+ static const bool test_at_bottom = false; |
+ JumpTarget loop(this, JumpTarget::BIDIRECTIONAL); |
+ JumpTarget body(this); |
+ |
// Compile the init expression if present. |
if (node->init() != NULL) { |
Visit(node->init()); |
@@ -2316,22 +2344,37 @@ |
// do not need to compile anything else. |
if (info == ALWAYS_FALSE) break; |
- // Based on the condition analysis, compile the test if |
- // necessary and label the body if necessary. |
+ // 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 if there is no update |
- // expression, otherwise with the body target. |
+ // the loop. |
if (node->next() == NULL) { |
+ // Use the continue target if there is no update expression. |
node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); |
node->continue_target()->Bind(); |
} else { |
+ // Otherwise use the backward loop target. |
node->continue_target()->Initialize(this); |
- body.Bind(); |
+ loop.Bind(); |
} |
} else { |
ASSERT(info == DONT_KNOW); |
- node->continue_target()->Initialize(this); |
+ 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()->Initialize(this); |
+ } else if (node->next() == NULL) { |
+ // We are not recompiling the test at the bottom and there |
+ // is no update expression. |
+ node->continue_target()->Initialize(this, 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()->Initialize(this); |
+ 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. |
@@ -2339,9 +2382,9 @@ |
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true); |
if (dest.false_was_fall_through()) { |
- // If we don't have dangling jumps to the body, the test is |
- // unconditionally false and we do not need to compile the |
- // body. |
+ // 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 |
@@ -2352,20 +2395,17 @@ |
} |
} |
- // The (stack check at the start of the) body was labeled. |
- // Compile it. |
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) { |
- // We did not use the continue target for the body. |
if (node->continue_target()->is_linked()) { |
node->continue_target()->Bind(); |
} |
// Control can reach the update by falling out of the body or |
- // by a continue in the body. |
+ // 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 |
@@ -2375,32 +2415,43 @@ |
} |
} |
- // Compile the test if necessary and jump back. |
+ // Based on the condition analysis, compile the backward jump as |
+ // necessary. |
if (info == ALWAYS_TRUE) { |
if (has_valid_frame()) { |
if (node->next() == NULL) { |
node->continue_target()->Jump(); |
} else { |
- body.Jump(); |
+ loop.Jump(); |
} |
} |
} else { |
ASSERT(info == DONT_KNOW); // ALWAYS_FALSE cannot reach here. |
- 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(); |
+ 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(); |
+ } |
+ } |
} |
- |
- // 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); |
- } |
} |
// The break target may be already bound (by the condition), or |