| Index: src/x64/codegen-x64.cc
|
| diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
|
| index d58dd0226e3875c29d8548874974e4e37f76cd6c..2c65dc74df936e7d126a5e24f359fb8a7b249086 100644
|
| --- a/src/x64/codegen-x64.cc
|
| +++ b/src/x64/codegen-x64.cc
|
| @@ -1600,11 +1600,130 @@ void CodeGenerator::SetTypeForStackSlot(Slot* slot, TypeInfo info) {
|
| }
|
|
|
|
|
| +void CodeGenerator::GenerateFastSmiLoop(ForStatement* node) {
|
| + // A fast smi loop is a for loop with an initializer
|
| + // that is a simple assignment of a smi to a stack variable,
|
| + // a test that is a simple test of that variable against a smi constant,
|
| + // and a step that is a increment/decrement of the variable, and
|
| + // where the variable isn't modified in the loop body.
|
| + // This guarantees that the variable is always a smi.
|
| +
|
| + Variable* loop_var = node->loop_variable();
|
| + Smi* initial_value = *Handle<Smi>::cast(node->init()
|
| + ->StatementAsSimpleAssignment()->value()->AsLiteral()->handle());
|
| + Smi* limit_value = *Handle<Smi>::cast(
|
| + node->cond()->AsCompareOperation()->right()->AsLiteral()->handle());
|
| + Token::Value compare_op =
|
| + node->cond()->AsCompareOperation()->op();
|
| + bool increments =
|
| + node->next()->StatementAsCountOperation()->op() == Token::INC;
|
| +
|
| + // Check that the condition isn't initially false.
|
| + bool initially_false = false;
|
| + int initial_int_value = initial_value->value();
|
| + int limit_int_value = limit_value->value();
|
| + switch (compare_op) {
|
| + case Token::LT:
|
| + initially_false = initial_int_value >= limit_int_value;
|
| + break;
|
| + case Token::LTE:
|
| + initially_false = initial_int_value > limit_int_value;
|
| + break;
|
| + case Token::GT:
|
| + initially_false = initial_int_value <= limit_int_value;
|
| + break;
|
| + case Token::GTE:
|
| + initially_false = initial_int_value < limit_int_value;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + if (initially_false) return;
|
| +
|
| + // Only check loop condition at the end.
|
| +
|
| + Visit(node->init());
|
| +
|
| + JumpTarget loop(JumpTarget::BIDIRECTIONAL);
|
| +
|
| + IncrementLoopNesting();
|
| + loop.Bind();
|
| +
|
| + // Set number type of the loop variable to smi.
|
| + CheckStack(); // TODO(1222600): ignore if body contains calls.
|
| +
|
| + SetTypeForStackSlot(loop_var->slot(), TypeInfo::Smi());
|
| + Visit(node->body());
|
| +
|
| + if (node->continue_target()->is_linked()) {
|
| + node->continue_target()->Bind();
|
| + }
|
| +
|
| + if (has_valid_frame()) {
|
| + CodeForStatementPosition(node);
|
| + Slot* loop_var_slot = loop_var->slot();
|
| + if (loop_var_slot->type() == Slot::LOCAL) {
|
| + frame_->PushLocalAt(loop_var_slot->index());
|
| + } else {
|
| + ASSERT(loop_var_slot->type() == Slot::PARAMETER);
|
| + frame_->PushParameterAt(loop_var_slot->index());
|
| + }
|
| + Result loop_var_result = frame_->Pop();
|
| + if (!loop_var_result.is_register()) {
|
| + loop_var_result.ToRegister();
|
| + }
|
| +
|
| + if (increments) {
|
| + __ SmiAddConstant(loop_var_result.reg(),
|
| + loop_var_result.reg(),
|
| + Smi::FromInt(1));
|
| + } else {
|
| + __ SmiSubConstant(loop_var_result.reg(),
|
| + loop_var_result.reg(),
|
| + Smi::FromInt(1));
|
| + }
|
| +
|
| + {
|
| + __ SmiCompare(loop_var_result.reg(), limit_value);
|
| + Condition condition;
|
| + switch (compare_op) {
|
| + case Token::LT:
|
| + condition = less;
|
| + break;
|
| + case Token::LTE:
|
| + condition = less_equal;
|
| + break;
|
| + case Token::GT:
|
| + condition = greater;
|
| + break;
|
| + case Token::GTE:
|
| + condition = greater_equal;
|
| + break;
|
| + default:
|
| + condition = never;
|
| + UNREACHABLE();
|
| + }
|
| + loop.Branch(condition);
|
| + }
|
| + loop_var_result.Unuse();
|
| + }
|
| + if (node->break_target()->is_linked()) {
|
| + node->break_target()->Bind();
|
| + }
|
| + DecrementLoopNesting();
|
| +}
|
| +
|
| +
|
| void CodeGenerator::VisitForStatement(ForStatement* node) {
|
| ASSERT(!in_spilled_code());
|
| Comment cmnt(masm_, "[ ForStatement");
|
| CodeForStatementPosition(node);
|
|
|
| + if (node->is_fast_smi_loop()) {
|
| + GenerateFastSmiLoop(node);
|
| + return;
|
| + }
|
| +
|
| // Compile the init expression if present.
|
| if (node->init() != NULL) {
|
| Visit(node->init());
|
| @@ -1694,16 +1813,6 @@ void CodeGenerator::VisitForStatement(ForStatement* node) {
|
|
|
| CheckStack(); // TODO(1222600): ignore if body contains calls.
|
|
|
| - // We know that the loop index is a smi if it is not modified in the
|
| - // loop body and it is checked against a constant limit in the loop
|
| - // condition. In this case, we reset the static type information of the
|
| - // loop index to smi before compiling the body, the update expression, and
|
| - // the bottom check of the loop condition.
|
| - if (node->is_fast_smi_loop()) {
|
| - // Set number type of the loop variable to smi.
|
| - SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi());
|
| - }
|
| -
|
| Visit(node->body());
|
|
|
| // If there is an update expression, compile it if necessary.
|
| @@ -1723,13 +1832,6 @@ void CodeGenerator::VisitForStatement(ForStatement* node) {
|
| }
|
| }
|
|
|
| - // Set the type of the loop variable to smi before compiling the test
|
| - // expression if we are in a fast smi loop condition.
|
| - if (node->is_fast_smi_loop() && has_valid_frame()) {
|
| - // Set number type of the loop variable to smi.
|
| - SetTypeForStackSlot(node->loop_variable()->slot(), TypeInfo::Smi());
|
| - }
|
| -
|
| // Based on the condition analysis, compile the backward jump as
|
| // necessary.
|
| switch (info) {
|
|
|