Author: [email protected]
Date: Tue Feb 24 01:21:25 2009
New Revision: 1344

Modified:
    branches/experimental/toiger/src/codegen-ia32.cc

Log:
Experimental: restore the test at the bottom of for and while loops.
In order to satisfy the requirement that a virtual frame has to reach
the body when we compile it, the test is duplicated and appears at
both the top and bottom of the loop.

Review URL: http://codereview.chromium.org/27084

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Tue Feb 24 01:21:25  
2009
@@ -2249,46 +2249,72 @@
      }

      case LoopStatement::WHILE_LOOP: {
+      JumpTarget body(this, JumpTarget::BIDIRECTIONAL);
        IncrementLoopNesting();

-      // If the test is never true and has no side effects there is no need
-      // to compile the test or body.
+      // If the condition is always false and has no side effects, we
+      // do not need to compile anything.
        if (info == ALWAYS_FALSE) break;

-      // Label the top of the loop with the continue target for the  
backward
-      // CFG edge.
-      node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
-      node->continue_target()->Bind();
-
-      // If the test is always true and has no side effects there is no  
need
-      // to compile it.  We only compile the test when we do not know its
-      // outcome or it may have side effects.
-      JumpTarget body(this);
-      ControlDestination dest(&body, node->break_target(), true);
-      if (info == DONT_KNOW) {
+      // Based on the condition analysis, compile the test if
+      // necessary and label the body if 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()->Initialize(this,  
JumpTarget::BIDIRECTIONAL);
+        node->continue_target()->Bind();
+      } else {
+        ASSERT(info == DONT_KNOW);  // ALWAYS_FALSE cannot reach here.
+        node->continue_target()->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.
+        ControlDestination dest(&body, node->break_target(), true);
          LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &dest, true);
-      }

-      if (dest.false_was_fall_through()) {
-        // The break target was bound.  We may have dangling jumps to
-        // the body.
-        if (!body.is_linked()) break;
-
-        // We have dangling jumps to the body target.
-        node->break_target()->Unuse();
-        node->break_target()->Jump();
-        body.Bind();
+        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 (!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();
+        }
        }

-      // The body target has just been bound or else we didn't compile
-      // the test.
+      // 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 control flow can fall out of the body, jump back to the top.
-      if (has_valid_frame()) {
-        node->continue_target()->Jump();
+      // Compile the test if necessary and jump back.
+      if (info == ALWAYS_TRUE) {
+        // The 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 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
+      // there may not be a valid frame.  Bind it only if needed.
        if (node->break_target()->is_linked()) {
          node->break_target()->Bind();
        }
@@ -2296,80 +2322,111 @@
      }

      case LoopStatement::FOR_LOOP: {
-      JumpTarget loop(this, JumpTarget::BIDIRECTIONAL);
+      JumpTarget body(this, JumpTarget::BIDIRECTIONAL);
+
+      // Compile the init expression if present.
        if (node->init() != NULL) {
          Visit(node->init());
        }

        IncrementLoopNesting();
-      // If the test is never true and has no side effects there is no need
-      // to compile the test or body.
+
+      // If the condition is always false and has no side effects, we
+      // do not need to compile anything else.
        if (info == ALWAYS_FALSE) break;

-      // Label the top of the loop for the backward CFG edge.  If there is
-      // no update expression we can use the continue target.
-      if (node->next() == NULL) {
-        node->continue_target()->Initialize(this,  
JumpTarget::BIDIRECTIONAL);
-        node->continue_target()->Bind();
+      // Based on the condition analysis, compile the test if
+      // necessary and label the body if 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.
+        if (node->next() == NULL) {
+          node->continue_target()->Initialize(this,  
JumpTarget::BIDIRECTIONAL);
+          node->continue_target()->Bind();
+        } else {
+          node->continue_target()->Initialize(this);
+          body.Bind();
+        }
        } else {
+        ASSERT(info == DONT_KNOW);
          node->continue_target()->Initialize(this);
-        loop.Bind();
-      }
-
-      // If the test is always true and has no side effects there is no  
need
-      // to compile it.  We only compile the test when we do not know its
-      // outcome or it has side effects.
-      JumpTarget body(this);
-      ControlDestination dest(&body, node->break_target(), true);
-      if (info == DONT_KNOW) {
+        // 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()) {
-        // The break target was bound.  We may have dangling jumps to
-        // the body.
-        if (!body.is_linked()) break;
-
-        node->break_target()->Unuse();
-        node->break_target()->Jump();
-        body.Bind();
+        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 (!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();
+        }
        }

-      // The body target has just been bound or else we didn't compile
-      // the test.
+      // 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 (node->next() == NULL) {
-        // If there is no update statement and control flow can fall out
-        // of the loop, jump to the continue label.
-        if (has_valid_frame()) {
-          node->continue_target()->Jump();
+      // 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();
          }
-        if (node->break_target()->is_linked()) {
-          node->break_target()->Bind();
+
+        // Control can reach the update by falling out of the body or
+        // by a continue in the body.
+        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());
          }
+      }

+      // Compile the test if necessary and jump back.
+      if (info == ALWAYS_TRUE) {
+        if (has_valid_frame()) {
+          if (node->next() == NULL) {
+            node->continue_target()->Jump();
+          } else {
+            body.Jump();
+          }
+        }
        } else {
-        // If there is an update statement and control flow can reach it
-        // via falling out of the body of the loop or continuing, we
-        // compile the update statement.
+        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();
          }
+
+        // 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 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());
-          loop.Jump();
-        }
-        if (node->break_target()->is_linked()) {
-          node->break_target()->Bind();
+          // 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
+      // there may not be a valid frame.  Bind it only if needed.
+      if (node->break_target()->is_linked()) {
+        node->break_target()->Bind();
+      }
        break;
      }
    }

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to