From 4fd9ba90429a195c1790f7312b55fc3ce57a636f Mon Sep 17 00:00:00 2001 From: "yangguo@chromium.org" Date: Wed, 12 Nov 2014 08:25:59 +0000 Subject: [PATCH] Reland "Fix stepping in for-loops." BUG=v8:3634 LOG=N R=ulan@chromium.org Review URL: https://codereview.chromium.org/688243005 Cr-Commit-Position: refs/heads/master@{#25279} git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25279 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/full-codegen-arm.cc | 45 +--------- src/arm64/full-codegen-arm64.cc | 45 +--------- src/full-codegen.cc | 56 ++++++++++-- src/ia32/full-codegen-ia32.cc | 45 +--------- src/mips/full-codegen-mips.cc | 45 +--------- src/mips64/full-codegen-mips64.cc | 45 +--------- src/parser.cc | 39 +++++---- src/x64/full-codegen-x64.cc | 45 +--------- src/x87/full-codegen-x87.cc | 45 +--------- test/cctest/test-debug.cc | 26 +++--- test/mjsunit/debug-step.js | 2 +- test/mjsunit/es6/debug-stepnext-for.js | 116 +++++++++++++++++++++++++ 12 files changed, 220 insertions(+), 334 deletions(-) create mode 100644 test/mjsunit/es6/debug-stepnext-for.js diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index f4938a7297..4dca63c7f3 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1111,6 +1111,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); __ cmp(r0, ip); @@ -1214,6 +1215,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + // Load the current count to r0, load the length to r1. __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize)); __ cmp(r0, r1); // Compare to the array length. @@ -1283,48 +1286,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc index b693d59127..f2f036652a 100644 --- a/src/arm64/full-codegen-arm64.cc +++ b/src/arm64/full-codegen-arm64.cc @@ -1109,6 +1109,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, &exit); Register null_value = x15; @@ -1202,6 +1203,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ Bind(&loop); + SetExpressionPosition(stmt->each()); + // Load the current count to x0, load the length to x1. __ PeekPair(x0, x1, 0); __ Cmp(x0, x1); // Compare to the array length. @@ -1271,48 +1274,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ Bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ Bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ B(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ Bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new space for diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 01f2fafefa..237cdd6290 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -136,21 +136,19 @@ void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) { void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) { - // Mark for statements breakable if the condition expression is. - if (stmt->cond() != NULL) { - Visit(stmt->cond()); - } + // We set positions for both init and condition, if they exist. + if (stmt->cond() != NULL || stmt->init() != NULL) is_breakable_ = true; } void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) { - // Mark for in statements breakable if the enumerable expression is. - Visit(stmt->enumerable()); + // For-in is breakable because we set the position for the enumerable. + is_breakable_ = true; } void BreakableStatementChecker::VisitForOfStatement(ForOfStatement* stmt) { - // For-of is breakable because of the next() call. + // For-of is breakable because we set the position for the next() call. is_breakable_ = true; } @@ -1345,6 +1343,7 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { SetStatementPosition(stmt); if (stmt->init() != NULL) { + SetStatementPosition(stmt->init()); Visit(stmt->init()); } @@ -1359,6 +1358,7 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS); __ bind(loop_statement.continue_label()); if (stmt->next() != NULL) { + SetStatementPosition(stmt->next()); Visit(stmt->next()); } @@ -1371,6 +1371,7 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { __ bind(&test); if (stmt->cond() != NULL) { + SetExpressionPosition(stmt->cond()); VisitForControl(stmt->cond(), &body, loop_statement.break_label(), @@ -1385,6 +1386,47 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) { } +void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { + Comment cmnt(masm_, "[ ForOfStatement"); + SetStatementPosition(stmt); + + Iteration loop_statement(this, stmt); + increment_loop_depth(); + + // var iterator = iterable[Symbol.iterator](); + VisitForEffect(stmt->assign_iterator()); + + // Loop entry. + __ bind(loop_statement.continue_label()); + + // result = iterator.next() + SetExpressionPosition(stmt->next_result()); + VisitForEffect(stmt->next_result()); + + // if (result.done) break; + Label result_not_done; + VisitForControl(stmt->result_done(), loop_statement.break_label(), + &result_not_done, &result_not_done); + __ bind(&result_not_done); + + // each = result.value + VisitForEffect(stmt->assign_each()); + + // Generate code for the body of the loop. + Visit(stmt->body()); + + // Check stack before looping. + PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); + EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); + __ jmp(loop_statement.continue_label()); + + // Exit and decrement the loop depth. + PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); + __ bind(loop_statement.break_label()); + decrement_loop_depth(); +} + + void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { Comment cmnt(masm_, "[ TryCatchStatement"); SetStatementPosition(stmt); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index ab9438ab7e..310e1ce594 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -1045,6 +1045,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ cmp(eax, isolate()->factory()->undefined_value()); __ j(equal, &exit); @@ -1139,6 +1140,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. __ j(above_equal, loop_statement.break_label()); @@ -1205,48 +1208,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc index e685cc9110..9535de2da8 100644 --- a/src/mips/full-codegen-mips.cc +++ b/src/mips/full-codegen-mips.cc @@ -1102,6 +1102,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ mov(a0, result_register()); // Result as param to InvokeBuiltin below. __ LoadRoot(at, Heap::kUndefinedValueRootIndex); @@ -1201,6 +1202,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + // Load the current count to a0, load the length to a1. __ lw(a0, MemOperand(sp, 0 * kPointerSize)); __ lw(a1, MemOperand(sp, 1 * kPointerSize)); @@ -1270,48 +1273,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new diff --git a/src/mips64/full-codegen-mips64.cc b/src/mips64/full-codegen-mips64.cc index 06c3bb45b5..4fb5629af3 100644 --- a/src/mips64/full-codegen-mips64.cc +++ b/src/mips64/full-codegen-mips64.cc @@ -1097,6 +1097,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ mov(a0, result_register()); // Result as param to InvokeBuiltin below. __ LoadRoot(at, Heap::kUndefinedValueRootIndex); @@ -1196,6 +1197,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + // Load the current count to a0, load the length to a1. __ ld(a0, MemOperand(sp, 0 * kPointerSize)); __ ld(a1, MemOperand(sp, 1 * kPointerSize)); @@ -1265,48 +1268,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new diff --git a/src/parser.cc b/src/parser.cc index 4c813554e7..dafab10c1c 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -2941,7 +2941,7 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, // var iterator = subject[Symbol.iterator](); assign_iterator = factory()->NewAssignment( Token::ASSIGN, factory()->NewVariableProxy(iterator), - GetIterator(subject, factory()), RelocInfo::kNoPosition); + GetIterator(subject, factory()), subject->position()); // var result = iterator.next(); { @@ -2952,11 +2952,11 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, iterator_proxy, next_literal, RelocInfo::kNoPosition); ZoneList* next_arguments = new(zone()) ZoneList(0, zone()); - Expression* next_call = factory()->NewCall( - next_property, next_arguments, RelocInfo::kNoPosition); + Expression* next_call = factory()->NewCall(next_property, next_arguments, + subject->position()); Expression* result_proxy = factory()->NewVariableProxy(result); - next_result = factory()->NewAssignment( - Token::ASSIGN, result_proxy, next_call, RelocInfo::kNoPosition); + next_result = factory()->NewAssignment(Token::ASSIGN, result_proxy, + next_call, subject->position()); } // result.done @@ -2975,8 +2975,8 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt, Expression* result_proxy = factory()->NewVariableProxy(result); Expression* result_value = factory()->NewProperty( result_proxy, value_literal, RelocInfo::kNoPosition); - assign_each = factory()->NewAssignment( - Token::ASSIGN, each, result_value, RelocInfo::kNoPosition); + assign_each = factory()->NewAssignment(Token::ASSIGN, each, result_value, + each->position()); } for_of->Initialize(each, subject, body, @@ -3154,7 +3154,7 @@ Statement* Parser::ParseForStatement(ZoneList* labels, // ForStatement :: // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement - int pos = peek_position(); + int stmt_pos = peek_position(); Statement* init = NULL; ZoneList let_bindings(1, zone()); @@ -3177,19 +3177,20 @@ Statement* Parser::ParseForStatement(ZoneList* labels, CHECK_OK); bool accept_OF = decl_props == kHasNoInitializers; ForEachStatement::VisitMode mode; + int each_pos = position(); if (name != NULL && CheckInOrOf(accept_OF, &mode)) { Interface* interface = is_const ? Interface::NewConst() : Interface::NewValue(); ForEachStatement* loop = - factory()->NewForEachStatement(mode, labels, pos); + factory()->NewForEachStatement(mode, labels, stmt_pos); Target target(&this->target_stack_, loop); Expression* enumerable = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); VariableProxy* each = - scope_->NewUnresolved(factory(), name, interface); + scope_->NewUnresolved(factory(), name, interface, each_pos); Statement* body = ParseStatement(NULL, CHECK_OK); InitializeForEachStatement(loop, each, enumerable, body); Block* result = @@ -3216,6 +3217,7 @@ Statement* Parser::ParseForStatement(ZoneList* labels, bool accept_IN = name != NULL && decl_props != kHasInitializers; bool accept_OF = decl_props == kHasNoInitializers; ForEachStatement::VisitMode mode; + int each_pos = position(); if (accept_IN && CheckInOrOf(accept_OF, &mode)) { // Rewrite a for-in statement of the form @@ -3235,9 +3237,9 @@ Statement* Parser::ParseForStatement(ZoneList* labels, // implementing stack allocated block scoped variables. Variable* temp = scope_->DeclarationScope()->NewTemporary( ast_value_factory()->dot_for_string()); - VariableProxy* temp_proxy = factory()->NewVariableProxy(temp); + VariableProxy* temp_proxy = factory()->NewVariableProxy(temp, each_pos); ForEachStatement* loop = - factory()->NewForEachStatement(mode, labels, pos); + factory()->NewForEachStatement(mode, labels, stmt_pos); Target target(&this->target_stack_, loop); // The expression does not see the loop variable. @@ -3246,7 +3248,8 @@ Statement* Parser::ParseForStatement(ZoneList* labels, scope_ = for_scope; Expect(Token::RPAREN, CHECK_OK); - VariableProxy* each = scope_->NewUnresolved(factory(), name); + VariableProxy* each = scope_->NewUnresolved( + factory(), name, Interface::NewValue(), each_pos); Statement* body = ParseStatement(NULL, CHECK_OK); Block* body_block = factory()->NewBlock(NULL, 3, false, RelocInfo::kNoPosition); @@ -3280,7 +3283,7 @@ Statement* Parser::ParseForStatement(ZoneList* labels, expression, lhs_location, "invalid_lhs_in_for", CHECK_OK); ForEachStatement* loop = - factory()->NewForEachStatement(mode, labels, pos); + factory()->NewForEachStatement(mode, labels, stmt_pos); Target target(&this->target_stack_, loop); Expression* enumerable = ParseExpression(true, CHECK_OK); @@ -3296,14 +3299,13 @@ Statement* Parser::ParseForStatement(ZoneList* labels, return loop; } else { - init = factory()->NewExpressionStatement( - expression, RelocInfo::kNoPosition); + init = factory()->NewExpressionStatement(expression, position()); } } } // Standard 'for' loop - ForStatement* loop = factory()->NewForStatement(labels, pos); + ForStatement* loop = factory()->NewForStatement(labels, stmt_pos); Target target(&this->target_stack_, loop); // Parsed initializer at this point. @@ -3326,8 +3328,9 @@ Statement* Parser::ParseForStatement(ZoneList* labels, Statement* next = NULL; if (peek() != Token::RPAREN) { + int next_pos = position(); Expression* exp = ParseExpression(true, CHECK_OK); - next = factory()->NewExpressionStatement(exp, RelocInfo::kNoPosition); + next = factory()->NewExpressionStatement(exp, next_pos); } Expect(Token::RPAREN, CHECK_OK); diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc index cbee082060..66dc99a3bd 100644 --- a/src/x64/full-codegen-x64.cc +++ b/src/x64/full-codegen-x64.cc @@ -1067,6 +1067,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); __ j(equal, &exit); @@ -1170,6 +1171,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + __ movp(rax, Operand(rsp, 0 * kPointerSize)); // Get the current index. __ cmpp(rax, Operand(rsp, 1 * kPointerSize)); // Compare to the array length. __ j(above_equal, loop_statement.break_label()); @@ -1239,48 +1242,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new diff --git a/src/x87/full-codegen-x87.cc b/src/x87/full-codegen-x87.cc index 729655d80a..edb4f4690a 100644 --- a/src/x87/full-codegen-x87.cc +++ b/src/x87/full-codegen-x87.cc @@ -1034,6 +1034,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Get the object to enumerate over. If the object is null or undefined, skip // over the loop. See ECMA-262 version 5, section 12.6.4. + SetExpressionPosition(stmt->enumerable()); VisitForAccumulatorValue(stmt->enumerable()); __ cmp(eax, isolate()->factory()->undefined_value()); __ j(equal, &exit); @@ -1128,6 +1129,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { // Generate code for doing the condition check. PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS); __ bind(&loop); + SetExpressionPosition(stmt->each()); + __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index. __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length. __ j(above_equal, loop_statement.break_label()); @@ -1194,48 +1197,6 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { } -void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { - Comment cmnt(masm_, "[ ForOfStatement"); - SetStatementPosition(stmt); - - Iteration loop_statement(this, stmt); - increment_loop_depth(); - - // var iterator = iterable[Symbol.iterator](); - VisitForEffect(stmt->assign_iterator()); - - // Loop entry. - __ bind(loop_statement.continue_label()); - - // result = iterator.next() - VisitForEffect(stmt->next_result()); - - // if (result.done) break; - Label result_not_done; - VisitForControl(stmt->result_done(), - loop_statement.break_label(), - &result_not_done, - &result_not_done); - __ bind(&result_not_done); - - // each = result.value - VisitForEffect(stmt->assign_each()); - - // Generate code for the body of the loop. - Visit(stmt->body()); - - // Check stack before looping. - PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS); - EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label()); - __ jmp(loop_statement.continue_label()); - - // Exit and decrement the loop depth. - PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); - __ bind(loop_statement.break_label()); - decrement_loop_depth(); -} - - void FullCodeGenerator::EmitNewClosure(Handle info, bool pretenure) { // Use the fast case closure allocation code that allocates in new diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 5d38a16aee..677a292698 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -2860,7 +2860,7 @@ TEST(DebugStepKeyedLoadLoop) { foo->Call(env->Global(), kArgc, args); // With stepping all break locations are hit. - CHECK_EQ(35, break_point_hit_count); + CHECK_EQ(45, break_point_hit_count); v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); @@ -2908,7 +2908,7 @@ TEST(DebugStepKeyedStoreLoop) { foo->Call(env->Global(), kArgc, args); // With stepping all break locations are hit. - CHECK_EQ(34, break_point_hit_count); + CHECK_EQ(44, break_point_hit_count); v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); @@ -2952,7 +2952,7 @@ TEST(DebugStepNamedLoadLoop) { foo->Call(env->Global(), 0, NULL); // With stepping all break locations are hit. - CHECK_EQ(55, break_point_hit_count); + CHECK_EQ(65, break_point_hit_count); v8::Debug::SetDebugEventListener(NULL); CheckDebuggerUnloaded(); @@ -2995,9 +2995,7 @@ static void DoDebugStepNamedStoreLoop(int expected) { // Test of the stepping mechanism for named load in a loop. -TEST(DebugStepNamedStoreLoop) { - DoDebugStepNamedStoreLoop(24); -} +TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); } // Test the stepping mechanism with different ICs. @@ -3330,14 +3328,14 @@ TEST(DebugStepFor) { break_point_hit_count = 0; v8::Handle argv_10[argc] = { v8::Number::New(isolate, 10) }; foo->Call(env->Global(), argc, argv_10); - CHECK_EQ(23, break_point_hit_count); + CHECK_EQ(45, break_point_hit_count); // Looping 100 times. step_action = StepIn; break_point_hit_count = 0; v8::Handle argv_100[argc] = { v8::Number::New(isolate, 100) }; foo->Call(env->Global(), argc, argv_100); - CHECK_EQ(203, break_point_hit_count); + CHECK_EQ(405, break_point_hit_count); // Get rid of the debug event listener. v8::Debug::SetDebugEventListener(NULL); @@ -3381,7 +3379,7 @@ TEST(DebugStepForContinue) { v8::Handle argv_10[argc] = { v8::Number::New(isolate, 10) }; result = foo->Call(env->Global(), argc, argv_10); CHECK_EQ(5, result->Int32Value()); - CHECK_EQ(52, break_point_hit_count); + CHECK_EQ(62, break_point_hit_count); // Looping 100 times. step_action = StepIn; @@ -3389,7 +3387,7 @@ TEST(DebugStepForContinue) { v8::Handle argv_100[argc] = { v8::Number::New(isolate, 100) }; result = foo->Call(env->Global(), argc, argv_100); CHECK_EQ(50, result->Int32Value()); - CHECK_EQ(457, break_point_hit_count); + CHECK_EQ(557, break_point_hit_count); // Get rid of the debug event listener. v8::Debug::SetDebugEventListener(NULL); @@ -3434,7 +3432,7 @@ TEST(DebugStepForBreak) { v8::Handle argv_10[argc] = { v8::Number::New(isolate, 10) }; result = foo->Call(env->Global(), argc, argv_10); CHECK_EQ(9, result->Int32Value()); - CHECK_EQ(55, break_point_hit_count); + CHECK_EQ(64, break_point_hit_count); // Looping 100 times. step_action = StepIn; @@ -3442,7 +3440,7 @@ TEST(DebugStepForBreak) { v8::Handle argv_100[argc] = { v8::Number::New(isolate, 100) }; result = foo->Call(env->Global(), argc, argv_100); CHECK_EQ(99, result->Int32Value()); - CHECK_EQ(505, break_point_hit_count); + CHECK_EQ(604, break_point_hit_count); // Get rid of the debug event listener. v8::Debug::SetDebugEventListener(NULL); @@ -3473,7 +3471,7 @@ TEST(DebugStepForIn) { step_action = StepIn; break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); - CHECK_EQ(6, break_point_hit_count); + CHECK_EQ(8, break_point_hit_count); // Create a function for testing stepping. Run it to allow it to get // optimized. @@ -3490,7 +3488,7 @@ TEST(DebugStepForIn) { step_action = StepIn; break_point_hit_count = 0; foo->Call(env->Global(), 0, NULL); - CHECK_EQ(8, break_point_hit_count); + CHECK_EQ(10, break_point_hit_count); // Get rid of the debug event listener. v8::Debug::SetDebugEventListener(NULL); diff --git a/test/mjsunit/debug-step.js b/test/mjsunit/debug-step.js index 2233e36c66..45f077f967 100644 --- a/test/mjsunit/debug-step.js +++ b/test/mjsunit/debug-step.js @@ -68,7 +68,7 @@ bp1 = Debug.setBreakPoint(f, 1); state = 0; result = -1; f(); -assertEquals(499, result); +assertEquals(332, result); // Check that performing 1000 steps with a break point on the statement in the // for loop (line 2) will only make i 0 as a real break point breaks even when diff --git a/test/mjsunit/es6/debug-stepnext-for.js b/test/mjsunit/es6/debug-stepnext-for.js new file mode 100644 index 0000000000..98af911ae3 --- /dev/null +++ b/test/mjsunit/es6/debug-stepnext-for.js @@ -0,0 +1,116 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-debug-as debug --harmony + +Debug = debug.Debug; +var break_count = 0 +var exception = null; +var log = [] + +var s = 0; +var a = [1, 2, 3]; +var i = 0; + +function f() { + "use strict"; + debugger; // Break a + var j; // Break b + + for (var i in null) { // Break c + s += a[i]; + } + + for (j in null) { // Break d + s += a[j]; + } + + for (var i in a) { // Break e + s += a[i]; // Break E + } + + for (j in a) { // Break f + s += a[j]; // Break F + } + + for (let i in a) { // Break g + s += a[i]; // Break G + } + + for (var i of a) { // Break h + s += i; // Break H + } + + for (j of a) { // Break i + s += j; // Break I + } + + for (let i of a) { // Break j + s += i; // Break J + } + + for (var i = 0; i < 3; i++) { // Break k + s += a[i]; // Break K + } + + for (j = 0; j < 3; j++) { // Break l + s += a[j]; // Break L + } + + // TODO(yangguo): add test case for for-let. +} // Break y + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + var line = exec_state.frame(0).sourceLineText(); + var col = exec_state.frame(0).sourceColumn(); + print(line); + var match = line.match(/\/\/ Break (\w)$/); + assertEquals(2, match.length); + log.push(match[1] + col); + exec_state.prepareStep(Debug.StepAction.StepNext, 1); + break_count++; + } catch (e) { + exception = e; + } +} + +Debug.setListener(listener); +f(); +Debug.setListener(null); // Break z + +print(JSON.stringify(log)); +// The let declaration differs from var in that the loop variable +// is declared in every iteration. +var expected = [ + // Entry + "a2","b2", + // Empty for-in-var: var decl, get enumerable + "c7","c16", + // Empty for-in: get enumerable + "d12", + // For-in-var: var decl, get enumerable, assign, body, assign, body, ... + "e7","e16","e11","E4","e11","E4","e11","E4","e11", + // For-in: get enumerable, assign, body, assign, body, ... + "f12","f7","F4","f7","F4","f7","F4","f7", + // For-in-let: get enumerable, next, new let, body, next, new let, ... + "g16","g11","g7","G4","g11","g7","G4","g11","g7","G4","g11", + // For-of-var: var decl, next(), body, next(), body, ... + "h7","h16","H4","h16","H4","h16","H4","h16", + // For-of: next(), body, next(), body, ... + "i12","I4","i12","I4","i12","I4","i12", + // For-of-let: next(), new let, body, next(), new let, ... + "j16","j7","J4","j16","j7","J4","j16","j7","J4","j16", + // For-var: var decl, condition, body, next, condition, body, ... + "k7","k20","K4","k23","k20","K4","k23","k20","K4","k23","k20", + // For: init, condition, body, next, condition, body, ... + "l11","l16","L4","l19","l16","L4","l19","l16","L4","l19","l16", + // Exit. + "y0","z0", +] + +assertArrayEquals(expected, log); +assertEquals(48, s); +assertNull(exception);