Chromium Code Reviews| Index: src/hydrogen.cc |
| diff --git a/src/hydrogen.cc b/src/hydrogen.cc |
| index 30cc08839a5dd64a31cf795f822bf34be0232c8b..4fc77f945b921a9b94ad19e49bf3edc14a9a7173 100644 |
| --- a/src/hydrogen.cc |
| +++ b/src/hydrogen.cc |
| @@ -3148,65 +3148,70 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
| HValue* value, |
| ZoneMapList* types, |
| Handle<String> name) { |
| - int number_of_types = Min(types->length(), kMaxStorePolymorphism); |
| - ZoneMapList maps(number_of_types); |
| - ZoneList<HSubgraph*> subgraphs(number_of_types); |
| - bool needs_generic = (types->length() > kMaxStorePolymorphism); |
| - |
| - // Build subgraphs for each of the specific maps. |
| - // |
| - // TODO(ager): We should recognize when the prototype chains for |
| - // different maps are identical. In that case we can avoid |
| - // repeatedly generating the same prototype map checks. |
| - for (int i = 0; i < number_of_types; ++i) { |
| + int count = 0; |
| + HBasicBlock* join = NULL; |
| + for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
| Handle<Map> map = types->at(i); |
| LookupResult lookup; |
| if (ComputeStoredField(map, name, &lookup)) { |
| - HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
| - SubgraphScope scope(this, subgraph); |
| + ++count; |
| + if (join == NULL) { |
| + AddInstruction(new HCheckNonSmi(object)); // Only needed once. |
| + join = graph()->CreateBasicBlock(); |
| + } |
| + HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| + HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| + HCompareMap* compare = new HCompareMap(object, map, if_true, if_false); |
| + current_block()->Finish(compare); |
| + |
| + set_current_block(if_true); |
| HInstruction* instr = |
| BuildStoreNamedField(object, name, value, map, &lookup, false); |
| - Push(value); |
| instr->set_position(expr->position()); |
| + // Goto will add the HSimulate for the store. |
| AddInstruction(instr); |
| - maps.Add(map); |
| - subgraphs.Add(subgraph); |
| - } else { |
| - needs_generic = true; |
| + if (!ast_context()->IsEffect()) Push(value); |
| + current_block()->Goto(join); |
| + |
| + set_current_block(if_false); |
| } |
| } |
| - // If none of the properties were named fields we generate a |
| - // generic store. |
| - if (maps.length() == 0) { |
| + // Finish up. We need a generic IC if there were types we couldn't |
| + // resolve statically or if we want to handle maps we've never seen. |
| + if (count < types->length() || !FLAG_deoptimize_uncommon_cases) { |
| HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
|
fschneider
2011/03/03 16:59:57
Maybe BuildStoreNamedGeneric should return a HStor
|
| - Push(value); |
| instr->set_position(expr->position()); |
| AddInstruction(instr); |
| - if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
| - ast_context()->ReturnValue(Pop()); |
| - } else { |
| - // Build subgraph for generic store through IC. |
| - HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
| - { SubgraphScope scope(this, default_graph); |
| - if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
| - default_graph->exit_block()->FinishExit(new HDeoptimize()); |
| - default_graph->set_exit_block(NULL); |
| - } else { |
| - HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
| - Push(value); |
| - instr->set_position(expr->position()); |
| - AddInstruction(instr); |
| + |
| + if (join == NULL) { |
| + // The HSimulate for the store should not see the stored value in |
| + // effect contexts (it is not materialized at expr->id() in the |
| + // unoptimized code). |
| + if (instr->HasSideEffects()) { |
| + if (ast_context()->IsEffect()) { |
| + AddSimulate(expr->id()); |
| + } else { |
| + Push(value); |
| + AddSimulate(expr->id()); |
| + Drop(1); |
| + } |
| } |
| + ast_context()->ReturnValue(value); |
| + } else { |
| + if (!ast_context()->IsEffect()) Push(value); |
| + current_block()->Goto(join); |
| + join->SetJoinId(expr->id()); |
| + set_current_block(join); |
| + if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| } |
| - HBasicBlock* new_exit_block = |
| - BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
| - set_current_block(new_exit_block); |
| - // In an effect context, we did not materialized the value in the |
| - // predecessor environments so there's no need to handle it here. |
| - if (current_block() != NULL && !ast_context()->IsEffect()) { |
| - ast_context()->ReturnValue(Pop()); |
| + } else { |
| + current_block()->FinishExit(new HDeoptimize); |
| + set_current_block(join); |
| + if (join != NULL) { |
| + join->SetJoinId(expr->id()); |
| + if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| } |
| } |
| } |