| Index: src/arm/codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/codegen-arm.cc (revision 3045)
|
| +++ src/arm/codegen-arm.cc (working copy)
|
| @@ -1539,191 +1539,200 @@
|
| }
|
|
|
|
|
| -void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
|
| +void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) {
|
| #ifdef DEBUG
|
| int original_height = frame_->height();
|
| #endif
|
| VirtualFrame::SpilledScope spilled_scope;
|
| - Comment cmnt(masm_, "[ LoopStatement");
|
| + Comment cmnt(masm_, "[ DoWhileStatement");
|
| CodeForStatementPosition(node);
|
| node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| + JumpTarget body(JumpTarget::BIDIRECTIONAL);
|
|
|
| - // 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;
|
| - }
|
| - }
|
| + // 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.
|
| + ConditionAnalysis info = AnalyzeCondition(node->cond());
|
| + switch (info) {
|
| + case ALWAYS_TRUE:
|
| + node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
|
| + node->continue_target()->Bind();
|
| + break;
|
| + case ALWAYS_FALSE:
|
| + node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| + break;
|
| + case DONT_KNOW:
|
| + node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| + body.Bind();
|
| + break;
|
| }
|
|
|
| - switch (node->type()) {
|
| - case LoopStatement::DO_LOOP: {
|
| - JumpTarget body(JumpTarget::BIDIRECTIONAL);
|
| + CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| + VisitAndSpill(node->body());
|
|
|
| - // 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.
|
| - if (info == ALWAYS_TRUE) {
|
| - node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
|
| + // Compile the test.
|
| + switch (info) {
|
| + case ALWAYS_TRUE:
|
| + // If control can fall off the end of the body, jump back to the
|
| + // top.
|
| + if (has_valid_frame()) {
|
| + node->continue_target()->Jump();
|
| + }
|
| + break;
|
| + case ALWAYS_FALSE:
|
| + // If we have a continue in the body, we only have to bind its
|
| + // jump target.
|
| + if (node->continue_target()->is_linked()) {
|
| node->continue_target()->Bind();
|
| - } else if (info == ALWAYS_FALSE) {
|
| - node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| - } else {
|
| - ASSERT(info == DONT_KNOW);
|
| - node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| - body.Bind();
|
| }
|
| -
|
| - CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| - VisitAndSpill(node->body());
|
| -
|
| - // Compile the test.
|
| - if (info == ALWAYS_TRUE) {
|
| + 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()) {
|
| + LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
|
| + &body, node->break_target(), true);
|
| if (has_valid_frame()) {
|
| - // If control can fall off the end of the body, jump back to the
|
| - // top.
|
| - node->continue_target()->Jump();
|
| + // A invalid frame here indicates that control did not
|
| + // fall out of the test expression.
|
| + Branch(true, &body);
|
| }
|
| - } else if (info == ALWAYS_FALSE) {
|
| - // If we have a continue in the body, we only have to bind its jump
|
| - // target.
|
| - if (node->continue_target()->is_linked()) {
|
| - node->continue_target()->Bind();
|
| - }
|
| - } 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.
|
| - if (node->continue_target()->is_linked()) {
|
| - node->continue_target()->Bind();
|
| - }
|
| - if (has_valid_frame()) {
|
| - LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
|
| - &body, node->break_target(), true);
|
| - if (has_valid_frame()) {
|
| - // A invalid frame here indicates that control did not
|
| - // fall out of the test expression.
|
| - Branch(true, &body);
|
| - }
|
| - }
|
| }
|
| break;
|
| - }
|
| + }
|
|
|
| - case LoopStatement::WHILE_LOOP: {
|
| - // If the test is never true and has no side effects there is no need
|
| - // to compile the test or body.
|
| - if (info == ALWAYS_FALSE) break;
|
| + if (node->break_target()->is_linked()) {
|
| + node->break_target()->Bind();
|
| + }
|
| + ASSERT(!has_valid_frame() || frame_->height() == original_height);
|
| +}
|
|
|
| - // Label the top of the loop with the continue target for the backward
|
| - // CFG edge.
|
| - node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
|
| - node->continue_target()->Bind();
|
|
|
| - if (info == DONT_KNOW) {
|
| - JumpTarget body;
|
| - LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
|
| - &body, node->break_target(), true);
|
| - if (has_valid_frame()) {
|
| - // A NULL frame indicates that control did not fall out of the
|
| - // test expression.
|
| - Branch(false, node->break_target());
|
| - }
|
| - if (has_valid_frame() || body.is_linked()) {
|
| - body.Bind();
|
| - }
|
| - }
|
| +void CodeGenerator::VisitWhileStatement(WhileStatement* node) {
|
| +#ifdef DEBUG
|
| + int original_height = frame_->height();
|
| +#endif
|
| + VirtualFrame::SpilledScope spilled_scope;
|
| + Comment cmnt(masm_, "[ WhileStatement");
|
| + CodeForStatementPosition(node);
|
|
|
| - if (has_valid_frame()) {
|
| - CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| - VisitAndSpill(node->body());
|
| + // If the test is never true and has no side effects there is no need
|
| + // to compile the test or body.
|
| + ConditionAnalysis info = AnalyzeCondition(node->cond());
|
| + if (info == ALWAYS_FALSE) return;
|
|
|
| - // If control flow can fall out of the body, jump back to the top.
|
| - if (has_valid_frame()) {
|
| - node->continue_target()->Jump();
|
| - }
|
| - }
|
| - break;
|
| + node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| +
|
| + // Label the top of the loop with the continue target for the backward
|
| + // CFG edge.
|
| + node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
|
| + node->continue_target()->Bind();
|
| +
|
| + if (info == DONT_KNOW) {
|
| + JumpTarget body;
|
| + LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
|
| + &body, node->break_target(), true);
|
| + if (has_valid_frame()) {
|
| + // A NULL frame indicates that control did not fall out of the
|
| + // test expression.
|
| + Branch(false, node->break_target());
|
| }
|
| + if (has_valid_frame() || body.is_linked()) {
|
| + body.Bind();
|
| + }
|
| + }
|
|
|
| - case LoopStatement::FOR_LOOP: {
|
| - JumpTarget loop(JumpTarget::BIDIRECTIONAL);
|
| + if (has_valid_frame()) {
|
| + CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| + VisitAndSpill(node->body());
|
|
|
| - if (node->init() != NULL) {
|
| - VisitAndSpill(node->init());
|
| - }
|
| + // If control flow can fall out of the body, jump back to the top.
|
| + if (has_valid_frame()) {
|
| + node->continue_target()->Jump();
|
| + }
|
| + }
|
| + if (node->break_target()->is_linked()) {
|
| + node->break_target()->Bind();
|
| + }
|
| + ASSERT(!has_valid_frame() || frame_->height() == original_height);
|
| +}
|
|
|
| - // There is no need to compile the test or body.
|
| - if (info == ALWAYS_FALSE) break;
|
|
|
| - // If there is no update statement, label the top of the loop with the
|
| - // continue target, otherwise with the loop target.
|
| - if (node->next() == NULL) {
|
| - node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
|
| - node->continue_target()->Bind();
|
| - } else {
|
| - node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| - loop.Bind();
|
| - }
|
| +void CodeGenerator::VisitForStatement(ForStatement* node) {
|
| +#ifdef DEBUG
|
| + int original_height = frame_->height();
|
| +#endif
|
| + VirtualFrame::SpilledScope spilled_scope;
|
| + Comment cmnt(masm_, "[ ForStatement");
|
| + CodeForStatementPosition(node);
|
| + if (node->init() != NULL) {
|
| + VisitAndSpill(node->init());
|
| + }
|
|
|
| - // If the test is always true, there is no need to compile it.
|
| - if (info == DONT_KNOW) {
|
| - JumpTarget body;
|
| - LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
|
| - &body, node->break_target(), true);
|
| - if (has_valid_frame()) {
|
| - Branch(false, node->break_target());
|
| - }
|
| - if (has_valid_frame() || body.is_linked()) {
|
| - body.Bind();
|
| - }
|
| - }
|
| + // If the test is never true there is no need to compile the test or
|
| + // body.
|
| + ConditionAnalysis info = AnalyzeCondition(node->cond());
|
| + if (info == ALWAYS_FALSE) return;
|
|
|
| + node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| +
|
| + // If there is no update statement, label the top of the loop with the
|
| + // continue target, otherwise with the loop target.
|
| + JumpTarget loop(JumpTarget::BIDIRECTIONAL);
|
| + if (node->next() == NULL) {
|
| + node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
|
| + node->continue_target()->Bind();
|
| + } else {
|
| + node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
|
| + loop.Bind();
|
| + }
|
| +
|
| + // If the test is always true, there is no need to compile it.
|
| + if (info == DONT_KNOW) {
|
| + JumpTarget body;
|
| + LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
|
| + &body, node->break_target(), true);
|
| + if (has_valid_frame()) {
|
| + Branch(false, node->break_target());
|
| + }
|
| + if (has_valid_frame() || body.is_linked()) {
|
| + body.Bind();
|
| + }
|
| + }
|
| +
|
| + if (has_valid_frame()) {
|
| + CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| + VisitAndSpill(node->body());
|
| +
|
| + if (node->next() == NULL) {
|
| + // If there is no update statement and control flow can fall out
|
| + // of the loop, jump directly to the continue label.
|
| if (has_valid_frame()) {
|
| - CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| - VisitAndSpill(node->body());
|
| -
|
| - if (node->next() == NULL) {
|
| - // If there is no update statement and control flow can fall out
|
| - // of the loop, jump directly to the continue label.
|
| - if (has_valid_frame()) {
|
| - node->continue_target()->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.
|
| - if (node->continue_target()->is_linked()) {
|
| - node->continue_target()->Bind();
|
| - }
|
| - 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);
|
| - VisitAndSpill(node->next());
|
| - loop.Jump();
|
| - }
|
| - }
|
| + node->continue_target()->Jump();
|
| }
|
| - break;
|
| + } 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.
|
| + if (node->continue_target()->is_linked()) {
|
| + node->continue_target()->Bind();
|
| + }
|
| + 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);
|
| + VisitAndSpill(node->next());
|
| + loop.Jump();
|
| + }
|
| }
|
| }
|
| -
|
| if (node->break_target()->is_linked()) {
|
| node->break_target()->Bind();
|
| }
|
| - node->continue_target()->Unuse();
|
| - node->break_target()->Unuse();
|
| ASSERT(!has_valid_frame() || frame_->height() == original_height);
|
| }
|
|
|
| @@ -1918,12 +1927,12 @@
|
| }
|
|
|
|
|
| -void CodeGenerator::VisitTryCatch(TryCatch* node) {
|
| +void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) {
|
| #ifdef DEBUG
|
| int original_height = frame_->height();
|
| #endif
|
| VirtualFrame::SpilledScope spilled_scope;
|
| - Comment cmnt(masm_, "[ TryCatch");
|
| + Comment cmnt(masm_, "[ TryCatchStatement");
|
| CodeForStatementPosition(node);
|
|
|
| JumpTarget try_block;
|
| @@ -2043,12 +2052,12 @@
|
| }
|
|
|
|
|
| -void CodeGenerator::VisitTryFinally(TryFinally* node) {
|
| +void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) {
|
| #ifdef DEBUG
|
| int original_height = frame_->height();
|
| #endif
|
| 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
|
|
|