| Index: src/hydrogen.cc
|
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc
|
| index de7d4236f69f5980ee95709879ff9057e8b1726e..aaf23a01d2ec61f8d9052f6c00aa9f11b8fd2e32 100644
|
| --- a/src/hydrogen.cc
|
| +++ b/src/hydrogen.cc
|
| @@ -2742,12 +2742,20 @@ void HGraphBuilder::VisitIfStatement(IfStatement* stmt) {
|
|
|
| HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get(
|
| BreakableStatement* stmt,
|
| - BreakType type) {
|
| + BreakType type,
|
| + int* drop_extra) {
|
| + *drop_extra = 0;
|
| BreakAndContinueScope* current = this;
|
| while (current != NULL && current->info()->target() != stmt) {
|
| + *drop_extra += current->info()->drop_extra();
|
| current = current->next();
|
| }
|
| ASSERT(current != NULL); // Always found (unless stack is malformed).
|
| +
|
| + if (type == BREAK) {
|
| + *drop_extra += current->info()->drop_extra();
|
| + }
|
| +
|
| HBasicBlock* block = NULL;
|
| switch (type) {
|
| case BREAK:
|
| @@ -2775,7 +2783,11 @@ void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - HBasicBlock* continue_block = break_scope()->Get(stmt->target(), CONTINUE);
|
| + int drop_extra = 0;
|
| + HBasicBlock* continue_block = break_scope()->Get(stmt->target(),
|
| + CONTINUE,
|
| + &drop_extra);
|
| + Drop(drop_extra);
|
| current_block()->Goto(continue_block);
|
| set_current_block(NULL);
|
| }
|
| @@ -2785,7 +2797,11 @@ void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - HBasicBlock* break_block = break_scope()->Get(stmt->target(), BREAK);
|
| + int drop_extra = 0;
|
| + HBasicBlock* break_block = break_scope()->Get(stmt->target(),
|
| + BREAK,
|
| + &drop_extra);
|
| + Drop(drop_extra);
|
| current_block()->Goto(break_block);
|
| set_current_block(NULL);
|
| }
|
| @@ -3146,7 +3162,6 @@ void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
|
|
|
| BreakAndContinueInfo break_info(stmt);
|
| if (current_block() != NULL) {
|
| - BreakAndContinueScope push(&break_info, this);
|
| CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
| }
|
| HBasicBlock* body_exit =
|
| @@ -3191,7 +3206,6 @@ void HGraphBuilder::VisitForStatement(ForStatement* stmt) {
|
|
|
| BreakAndContinueInfo break_info(stmt);
|
| if (current_block() != NULL) {
|
| - BreakAndContinueScope push(&break_info, this);
|
| CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
| }
|
| HBasicBlock* body_exit =
|
| @@ -3216,7 +3230,104 @@ void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
|
| ASSERT(!HasStackOverflow());
|
| ASSERT(current_block() != NULL);
|
| ASSERT(current_block()->HasPredecessor());
|
| - return Bailout("ForInStatement");
|
| +
|
| + if (!stmt->each()->IsVariableProxy() ||
|
| + !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) {
|
| + return Bailout("ForInStatement with non-local each variable");
|
| + }
|
| +
|
| + Variable* each_var = stmt->each()->AsVariableProxy()->var();
|
| +
|
| + CHECK_ALIVE(VisitForValue(stmt->enumerable()));
|
| + HValue* enumerable = Top(); // Leave enumerable at the top.
|
| +
|
| + HValue* context = environment()->LookupContext();
|
| +
|
| + HInstruction* map = AddInstruction(new(zone()) HForInPrepareMap(
|
| + context, enumerable));
|
| + AddSimulate(stmt->PrepareId());
|
| +
|
| + HInstruction* array = AddInstruction(
|
| + new(zone()) HForInCacheArray(
|
| + enumerable,
|
| + map,
|
| + DescriptorArray::kEnumCacheBridgeCacheIndex));
|
| +
|
| + HInstruction* array_length = AddInstruction(
|
| + new(zone()) HFixedArrayBaseLength(array));
|
| +
|
| + HInstruction* start_index = AddInstruction(new(zone()) HConstant(
|
| + Handle<Object>(Smi::FromInt(0)), Representation::Integer32()));
|
| +
|
| + Push(map);
|
| + Push(array);
|
| + Push(array_length);
|
| + Push(start_index);
|
| +
|
| + HInstruction* index_cache = AddInstruction(
|
| + new(zone()) HForInCacheArray(
|
| + enumerable,
|
| + map,
|
| + DescriptorArray::kEnumCacheBridgeIndicesCacheIndex));
|
| + HForInCacheArray::cast(array)->set_index_cache(
|
| + HForInCacheArray::cast(index_cache));
|
| +
|
| + HBasicBlock* loop_entry = CreateLoopHeaderBlock();
|
| + current_block()->Goto(loop_entry);
|
| + set_current_block(loop_entry);
|
| +
|
| + HValue* index = Top();
|
| +
|
| + // Check that we still have more keys.
|
| + HCompareIDAndBranch* compare_index =
|
| + new(zone()) HCompareIDAndBranch(index, array_length, Token::LT);
|
| + compare_index->SetInputRepresentation(Representation::Integer32());
|
| +
|
| + HBasicBlock* loop_body = graph()->CreateBasicBlock();
|
| + HBasicBlock* loop_successor = graph()->CreateBasicBlock();
|
| +
|
| + compare_index->SetSuccessorAt(0, loop_body);
|
| + compare_index->SetSuccessorAt(1, loop_successor);
|
| + current_block()->Finish(compare_index);
|
| +
|
| + set_current_block(loop_successor);
|
| + Drop(5);
|
| +
|
| + set_current_block(loop_body);
|
| +
|
| + HValue* key = AddInstruction(
|
| + new(zone()) HLoadKeyedFastElement(
|
| + array, index, HLoadKeyedFastElement::OMIT_HOLE_CHECK));
|
| +
|
| + // Check if the expected map still matches that of the enumerable.
|
| + // If not just deoptimize.
|
| + AddInstruction(new(zone()) HCheckMapValue(enumerable, map));
|
| +
|
| + Bind(each_var, key);
|
| +
|
| + BreakAndContinueInfo break_info(stmt, 5);
|
| + CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry, &break_info));
|
| +
|
| + HBasicBlock* body_exit =
|
| + JoinContinue(stmt, current_block(), break_info.continue_block());
|
| +
|
| + if (body_exit != NULL) {
|
| + set_current_block(body_exit);
|
| +
|
| + HValue* current_index = Pop();
|
| + PushAndAdd(
|
| + new(zone()) HAdd(context, current_index, graph()->GetConstant1()));
|
| +
|
| + body_exit = current_block();
|
| + }
|
| +
|
| + HBasicBlock* loop_exit = CreateLoop(stmt,
|
| + loop_entry,
|
| + body_exit,
|
| + loop_successor,
|
| + break_info.break_block());
|
| +
|
| + set_current_block(loop_exit);
|
| }
|
|
|
|
|
|
|