 Chromium Code Reviews
 Chromium Code Reviews Issue 9425045:
  Support fast case for-in in Crankshaft.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 9425045:
  Support fast case for-in in Crankshaft.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/hydrogen.cc | 
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc | 
| index de7d4236f69f5980ee95709879ff9057e8b1726e..41de0142fd47990b4b8522a973064ad40d4904ee 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,107 @@ 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( | 
| 
fschneider
2012/02/20 14:56:06
You could use PushAndAdd here in these cases.
 | 
| + Handle<Object>(Smi::FromInt(0)), Representation::Integer32())); | 
| + | 
| 
fschneider
2012/02/20 14:56:06
Remove \n.
 | 
| + | 
| + 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(); | 
| + HValue* next_index = AddInstruction( | 
| 
fschneider
2012/02/20 14:56:06
You could use PushAndAdd here.
 | 
| + new(zone()) HAdd(context, current_index, graph()->GetConstant1())); | 
| + | 
| + Push(next_index); | 
| + | 
| + body_exit = current_block(); | 
| + } | 
| + | 
| + HBasicBlock* loop_exit = CreateLoop(stmt, | 
| + loop_entry, | 
| + body_exit, | 
| + loop_successor, | 
| + break_info.break_block()); | 
| + | 
| + set_current_block(loop_exit); | 
| } |