OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 } | 99 } |
100 | 100 |
101 | 101 |
102 void HBasicBlock::AddInstruction(HInstruction* instr) { | 102 void HBasicBlock::AddInstruction(HInstruction* instr) { |
103 ASSERT(!IsStartBlock() || !IsFinished()); | 103 ASSERT(!IsStartBlock() || !IsFinished()); |
104 ASSERT(!instr->IsLinked()); | 104 ASSERT(!instr->IsLinked()); |
105 ASSERT(!IsFinished()); | 105 ASSERT(!IsFinished()); |
106 if (first_ == NULL) { | 106 if (first_ == NULL) { |
107 HBlockEntry* entry = new HBlockEntry(); | 107 HBlockEntry* entry = new HBlockEntry(); |
108 entry->InitializeAsFirst(this); | 108 entry->InitializeAsFirst(this); |
109 first_ = entry; | 109 first_ = last_ = entry; |
110 } | 110 } |
111 instr->InsertAfter(GetLastInstruction()); | 111 instr->InsertAfter(last_); |
| 112 last_ = instr; |
112 } | 113 } |
113 | 114 |
114 | 115 |
115 HInstruction* HBasicBlock::GetLastInstruction() { | |
116 if (end_ != NULL) return end_->previous(); | |
117 if (first_ == NULL) return NULL; | |
118 if (last_ == NULL) last_ = first_; | |
119 while (last_->next() != NULL) last_ = last_->next(); | |
120 return last_; | |
121 } | |
122 | |
123 | |
124 HSimulate* HBasicBlock::CreateSimulate(int id) { | 116 HSimulate* HBasicBlock::CreateSimulate(int id) { |
125 ASSERT(HasEnvironment()); | 117 ASSERT(HasEnvironment()); |
126 HEnvironment* environment = last_environment(); | 118 HEnvironment* environment = last_environment(); |
127 ASSERT(id == AstNode::kNoNumber || | 119 ASSERT(id == AstNode::kNoNumber || |
128 environment->closure()->shared()->VerifyBailoutId(id)); | 120 environment->closure()->shared()->VerifyBailoutId(id)); |
129 | 121 |
130 int push_count = environment->push_count(); | 122 int push_count = environment->push_count(); |
131 int pop_count = environment->pop_count(); | 123 int pop_count = environment->pop_count(); |
132 | 124 |
133 int length = environment->length(); | 125 int length = environment->length(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 UpdateEnvironment(env); | 163 UpdateEnvironment(env); |
172 } | 164 } |
173 | 165 |
174 | 166 |
175 void HBasicBlock::SetJoinId(int id) { | 167 void HBasicBlock::SetJoinId(int id) { |
176 int length = predecessors_.length(); | 168 int length = predecessors_.length(); |
177 ASSERT(length > 0); | 169 ASSERT(length > 0); |
178 for (int i = 0; i < length; i++) { | 170 for (int i = 0; i < length; i++) { |
179 HBasicBlock* predecessor = predecessors_[i]; | 171 HBasicBlock* predecessor = predecessors_[i]; |
180 ASSERT(predecessor->end()->IsGoto()); | 172 ASSERT(predecessor->end()->IsGoto()); |
181 HSimulate* simulate = HSimulate::cast(predecessor->GetLastInstruction()); | 173 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); |
182 // We only need to verify the ID once. | 174 // We only need to verify the ID once. |
183 ASSERT(i != 0 || | 175 ASSERT(i != 0 || |
184 predecessor->last_environment()->closure()->shared() | 176 predecessor->last_environment()->closure()->shared() |
185 ->VerifyBailoutId(id)); | 177 ->VerifyBailoutId(id)); |
186 simulate->set_ast_id(id); | 178 simulate->set_ast_id(id); |
187 } | 179 } |
188 } | 180 } |
189 | 181 |
190 | 182 |
191 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 183 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
(...skipping 2887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3079 } | 3071 } |
3080 ast_context()->ReturnValue(Pop()); | 3072 ast_context()->ReturnValue(Pop()); |
3081 } | 3073 } |
3082 | 3074 |
3083 | 3075 |
3084 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { | 3076 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { |
3085 BAILOUT("CatchExtensionObject"); | 3077 BAILOUT("CatchExtensionObject"); |
3086 } | 3078 } |
3087 | 3079 |
3088 | 3080 |
3089 HBasicBlock* HGraphBuilder::BuildTypeSwitch(ZoneMapList* maps, | 3081 HBasicBlock* HGraphBuilder::BuildTypeSwitch(HValue* receiver, |
3090 ZoneList<HSubgraph*>* subgraphs, | 3082 ZoneMapList* maps, |
3091 HValue* receiver, | 3083 ZoneList<HSubgraph*>* body_graphs, |
| 3084 HSubgraph* default_graph, |
3092 int join_id) { | 3085 int join_id) { |
3093 ASSERT(subgraphs->length() == (maps->length() + 1)); | 3086 ASSERT(maps->length() == body_graphs->length()); |
| 3087 HBasicBlock* join_block = graph()->CreateBasicBlock(); |
| 3088 AddInstruction(new HCheckNonSmi(receiver)); |
3094 | 3089 |
3095 // Build map compare subgraphs for all but the first map. | 3090 for (int i = 0; i < maps->length(); ++i) { |
3096 ZoneList<HSubgraph*> map_compare_subgraphs(maps->length() - 1); | 3091 // Build the branches, connect all the target subgraphs to the join |
3097 for (int i = maps->length() - 1; i > 0; --i) { | 3092 // block. Use the default as a target of the last branch. |
3098 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3093 HSubgraph* if_true = body_graphs->at(i); |
3099 SubgraphScope scope(this, subgraph); | 3094 HSubgraph* if_false = (i == maps->length() - 1) |
3100 HSubgraph* else_subgraph = | 3095 ? default_graph |
3101 (i == (maps->length() - 1)) | 3096 : CreateBranchSubgraph(environment()); |
3102 ? subgraphs->last() | 3097 HCompareMap* compare = |
3103 : map_compare_subgraphs.last(); | 3098 new HCompareMap(receiver, |
3104 HCompareMap* compare = new HCompareMap(receiver, | 3099 maps->at(i), |
3105 maps->at(i), | 3100 if_true->entry_block(), |
3106 subgraphs->at(i)->entry_block(), | 3101 if_false->entry_block()); |
3107 else_subgraph->entry_block()); | 3102 subgraph()->exit_block()->Finish(compare); |
3108 current_subgraph_->exit_block()->Finish(compare); | 3103 |
3109 map_compare_subgraphs.Add(subgraph); | 3104 if (if_true->HasExit()) { |
| 3105 // In an effect context the value of the type switch is not needed. |
| 3106 // There is no need to merge it at the join block only to discard it. |
| 3107 if (ast_context()->IsEffect()) { |
| 3108 if_true->exit_block()->last_environment()->Drop(1); |
| 3109 } |
| 3110 if_true->exit_block()->Goto(join_block); |
| 3111 } |
| 3112 |
| 3113 subgraph()->set_exit_block(if_false->exit_block()); |
3110 } | 3114 } |
3111 | 3115 |
3112 // Generate first map check to end the current block. | 3116 // Connect the default if necessary. |
3113 AddInstruction(new HCheckNonSmi(receiver)); | 3117 if (subgraph()->HasExit()) { |
3114 HSubgraph* else_subgraph = | 3118 if (ast_context()->IsEffect()) { |
3115 (maps->length() == 1) ? subgraphs->at(1) : map_compare_subgraphs.last(); | 3119 environment()->Drop(1); |
3116 HCompareMap* compare = new HCompareMap(receiver, | |
3117 Handle<Map>(maps->first()), | |
3118 subgraphs->first()->entry_block(), | |
3119 else_subgraph->entry_block()); | |
3120 current_subgraph_->exit_block()->Finish(compare); | |
3121 | |
3122 // Join all the call subgraphs in a new basic block and make | |
3123 // this basic block the current basic block. | |
3124 HBasicBlock* join_block = graph_->CreateBasicBlock(); | |
3125 for (int i = 0; i < subgraphs->length(); ++i) { | |
3126 HSubgraph* subgraph = subgraphs->at(i); | |
3127 if (subgraph->HasExit()) { | |
3128 // In an effect context the value of the type switch is not needed. | |
3129 // There is no need to merge it at the join block only to discard it. | |
3130 HBasicBlock* subgraph_exit = subgraph->exit_block(); | |
3131 if (ast_context()->IsEffect()) { | |
3132 subgraph_exit->last_environment()->Drop(1); | |
3133 } | |
3134 subgraph_exit->Goto(join_block); | |
3135 } | 3120 } |
| 3121 subgraph()->exit_block()->Goto(join_block); |
3136 } | 3122 } |
3137 | 3123 |
3138 if (join_block->predecessors()->is_empty()) return NULL; | 3124 if (join_block->predecessors()->is_empty()) return NULL; |
3139 join_block->SetJoinId(join_id); | 3125 join_block->SetJoinId(join_id); |
3140 return join_block; | 3126 return join_block; |
3141 } | 3127 } |
3142 | 3128 |
3143 | 3129 |
3144 // Sets the lookup result and returns true if the store can be inlined. | 3130 // Sets the lookup result and returns true if the store can be inlined. |
3145 static bool ComputeStoredField(Handle<Map> type, | 3131 static bool ComputeStoredField(Handle<Map> type, |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3231 } | 3217 } |
3232 | 3218 |
3233 | 3219 |
3234 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, | 3220 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, |
3235 HValue* object, | 3221 HValue* object, |
3236 HValue* value, | 3222 HValue* value, |
3237 ZoneMapList* types, | 3223 ZoneMapList* types, |
3238 Handle<String> name) { | 3224 Handle<String> name) { |
3239 int number_of_types = Min(types->length(), kMaxStorePolymorphism); | 3225 int number_of_types = Min(types->length(), kMaxStorePolymorphism); |
3240 ZoneMapList maps(number_of_types); | 3226 ZoneMapList maps(number_of_types); |
3241 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3227 ZoneList<HSubgraph*> subgraphs(number_of_types); |
3242 bool needs_generic = (types->length() > kMaxStorePolymorphism); | 3228 bool needs_generic = (types->length() > kMaxStorePolymorphism); |
3243 | 3229 |
3244 // Build subgraphs for each of the specific maps. | 3230 // Build subgraphs for each of the specific maps. |
3245 // | 3231 // |
3246 // TODO(ager): We should recognize when the prototype chains for | 3232 // TODO(ager): We should recognize when the prototype chains for |
3247 // different maps are identical. In that case we can avoid | 3233 // different maps are identical. In that case we can avoid |
3248 // repeatedly generating the same prototype map checks. | 3234 // repeatedly generating the same prototype map checks. |
3249 for (int i = 0; i < number_of_types; ++i) { | 3235 for (int i = 0; i < number_of_types; ++i) { |
3250 Handle<Map> map = types->at(i); | 3236 Handle<Map> map = types->at(i); |
3251 LookupResult lookup; | 3237 LookupResult lookup; |
3252 if (ComputeStoredField(map, name, &lookup)) { | 3238 if (ComputeStoredField(map, name, &lookup)) { |
3253 maps.Add(map); | |
3254 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3239 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
3255 SubgraphScope scope(this, subgraph); | 3240 SubgraphScope scope(this, subgraph); |
3256 HInstruction* instr = | 3241 HInstruction* instr = |
3257 BuildStoreNamedField(object, name, value, map, &lookup, false); | 3242 BuildStoreNamedField(object, name, value, map, &lookup, false); |
3258 Push(value); | 3243 Push(value); |
3259 instr->set_position(expr->position()); | 3244 instr->set_position(expr->position()); |
3260 AddInstruction(instr); | 3245 AddInstruction(instr); |
| 3246 maps.Add(map); |
3261 subgraphs.Add(subgraph); | 3247 subgraphs.Add(subgraph); |
3262 } else { | 3248 } else { |
3263 needs_generic = true; | 3249 needs_generic = true; |
3264 } | 3250 } |
3265 } | 3251 } |
3266 | 3252 |
3267 // If none of the properties were named fields we generate a | 3253 // If none of the properties were named fields we generate a |
3268 // generic store. | 3254 // generic store. |
3269 if (maps.length() == 0) { | 3255 if (maps.length() == 0) { |
3270 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3256 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
3271 Push(value); | 3257 Push(value); |
3272 instr->set_position(expr->position()); | 3258 instr->set_position(expr->position()); |
3273 AddInstruction(instr); | 3259 AddInstruction(instr); |
3274 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); | 3260 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); |
3275 ast_context()->ReturnValue(Pop()); | 3261 ast_context()->ReturnValue(Pop()); |
3276 } else { | 3262 } else { |
3277 // Build subgraph for generic store through IC. | 3263 // Build subgraph for generic store through IC. |
3278 { | 3264 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
3279 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3265 { SubgraphScope scope(this, default_graph); |
3280 SubgraphScope scope(this, subgraph); | |
3281 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3266 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
3282 subgraph->FinishExit(new HDeoptimize()); | 3267 default_graph->FinishExit(new HDeoptimize()); |
3283 } else { | 3268 } else { |
3284 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 3269 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
3285 Push(value); | 3270 Push(value); |
3286 instr->set_position(expr->position()); | 3271 instr->set_position(expr->position()); |
3287 AddInstruction(instr); | 3272 AddInstruction(instr); |
3288 } | 3273 } |
3289 subgraphs.Add(subgraph); | |
3290 } | 3274 } |
3291 | 3275 |
3292 HBasicBlock* new_exit_block = | 3276 HBasicBlock* new_exit_block = |
3293 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3277 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
3294 subgraph()->set_exit_block(new_exit_block); | 3278 subgraph()->set_exit_block(new_exit_block); |
3295 // In an effect context, we did not materialized the value in the | 3279 // In an effect context, we did not materialized the value in the |
3296 // predecessor environments so there's no need to handle it here. | 3280 // predecessor environments so there's no need to handle it here. |
3297 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { | 3281 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { |
3298 ast_context()->ReturnValue(Pop()); | 3282 ast_context()->ReturnValue(Pop()); |
3299 } | 3283 } |
3300 } | 3284 } |
3301 } | 3285 } |
3302 | 3286 |
3303 | 3287 |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3558 current_subgraph_->FinishExit(new HAbnormalExit); | 3542 current_subgraph_->FinishExit(new HAbnormalExit); |
3559 } | 3543 } |
3560 | 3544 |
3561 | 3545 |
3562 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, | 3546 void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr, |
3563 HValue* object, | 3547 HValue* object, |
3564 ZoneMapList* types, | 3548 ZoneMapList* types, |
3565 Handle<String> name) { | 3549 Handle<String> name) { |
3566 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); | 3550 int number_of_types = Min(types->length(), kMaxLoadPolymorphism); |
3567 ZoneMapList maps(number_of_types); | 3551 ZoneMapList maps(number_of_types); |
3568 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3552 ZoneList<HSubgraph*> subgraphs(number_of_types); |
3569 bool needs_generic = (types->length() > kMaxLoadPolymorphism); | 3553 bool needs_generic = (types->length() > kMaxLoadPolymorphism); |
3570 | 3554 |
3571 // Build subgraphs for each of the specific maps. | 3555 // Build subgraphs for each of the specific maps. |
3572 // | 3556 // |
3573 // TODO(ager): We should recognize when the prototype chains for | 3557 // TODO(ager): We should recognize when the prototype chains for |
3574 // different maps are identical. In that case we can avoid | 3558 // different maps are identical. In that case we can avoid |
3575 // repeatedly generating the same prototype map checks. | 3559 // repeatedly generating the same prototype map checks. |
3576 for (int i = 0; i < number_of_types; ++i) { | 3560 for (int i = 0; i < number_of_types; ++i) { |
3577 Handle<Map> map = types->at(i); | 3561 Handle<Map> map = types->at(i); |
3578 LookupResult lookup; | 3562 LookupResult lookup; |
3579 map->LookupInDescriptors(NULL, *name, &lookup); | 3563 map->LookupInDescriptors(NULL, *name, &lookup); |
3580 if (lookup.IsProperty() && lookup.type() == FIELD) { | 3564 if (lookup.IsProperty() && lookup.type() == FIELD) { |
3581 maps.Add(map); | |
3582 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3565 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
3583 SubgraphScope scope(this, subgraph); | 3566 SubgraphScope scope(this, subgraph); |
3584 HLoadNamedField* instr = | 3567 HLoadNamedField* instr = |
3585 BuildLoadNamedField(object, expr, map, &lookup, false); | 3568 BuildLoadNamedField(object, expr, map, &lookup, false); |
3586 instr->set_position(expr->position()); | 3569 instr->set_position(expr->position()); |
3587 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. | 3570 instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads. |
3588 PushAndAdd(instr); | 3571 PushAndAdd(instr); |
| 3572 maps.Add(map); |
3589 subgraphs.Add(subgraph); | 3573 subgraphs.Add(subgraph); |
3590 } else { | 3574 } else { |
3591 needs_generic = true; | 3575 needs_generic = true; |
3592 } | 3576 } |
3593 } | 3577 } |
3594 | 3578 |
3595 // If none of the properties were named fields we generate a | 3579 // If none of the properties were named fields we generate a |
3596 // generic load. | 3580 // generic load. |
3597 if (maps.length() == 0) { | 3581 if (maps.length() == 0) { |
3598 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3582 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
3599 instr->set_position(expr->position()); | 3583 instr->set_position(expr->position()); |
3600 ast_context()->ReturnInstruction(instr, expr->id()); | 3584 ast_context()->ReturnInstruction(instr, expr->id()); |
3601 } else { | 3585 } else { |
3602 // Build subgraph for generic load through IC. | 3586 // Build subgraph for generic load through IC. |
3603 { | 3587 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
3604 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3588 { SubgraphScope scope(this, default_graph); |
3605 SubgraphScope scope(this, subgraph); | |
3606 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3589 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
3607 subgraph->FinishExit(new HDeoptimize()); | 3590 default_graph->FinishExit(new HDeoptimize()); |
3608 } else { | 3591 } else { |
3609 HInstruction* instr = BuildLoadNamedGeneric(object, expr); | 3592 HInstruction* instr = BuildLoadNamedGeneric(object, expr); |
3610 instr->set_position(expr->position()); | 3593 instr->set_position(expr->position()); |
3611 PushAndAdd(instr); | 3594 PushAndAdd(instr); |
3612 } | 3595 } |
3613 subgraphs.Add(subgraph); | |
3614 } | 3596 } |
3615 | 3597 |
3616 HBasicBlock* new_exit_block = | 3598 HBasicBlock* new_exit_block = |
3617 BuildTypeSwitch(&maps, &subgraphs, object, expr->id()); | 3599 BuildTypeSwitch(object, &maps, &subgraphs, default_graph, expr->id()); |
3618 subgraph()->set_exit_block(new_exit_block); | 3600 subgraph()->set_exit_block(new_exit_block); |
3619 // In an effect context, we did not materialized the value in the | 3601 // In an effect context, we did not materialized the value in the |
3620 // predecessor environments so there's no need to handle it here. | 3602 // predecessor environments so there's no need to handle it here. |
3621 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { | 3603 if (subgraph()->HasExit() && !ast_context()->IsEffect()) { |
3622 ast_context()->ReturnValue(Pop()); | 3604 ast_context()->ReturnValue(Pop()); |
3623 } | 3605 } |
3624 } | 3606 } |
3625 } | 3607 } |
3626 | 3608 |
3627 | 3609 |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3884 } | 3866 } |
3885 | 3867 |
3886 | 3868 |
3887 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, | 3869 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, |
3888 HValue* receiver, | 3870 HValue* receiver, |
3889 ZoneMapList* types, | 3871 ZoneMapList* types, |
3890 Handle<String> name) { | 3872 Handle<String> name) { |
3891 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 3873 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
3892 int number_of_types = Min(types->length(), kMaxCallPolymorphism); | 3874 int number_of_types = Min(types->length(), kMaxCallPolymorphism); |
3893 ZoneMapList maps(number_of_types); | 3875 ZoneMapList maps(number_of_types); |
3894 ZoneList<HSubgraph*> subgraphs(number_of_types + 1); | 3876 ZoneList<HSubgraph*> subgraphs(number_of_types); |
3895 bool needs_generic = (types->length() > kMaxCallPolymorphism); | 3877 bool needs_generic = (types->length() > kMaxCallPolymorphism); |
3896 | 3878 |
3897 // Build subgraphs for each of the specific maps. | 3879 // Build subgraphs for each of the specific maps. |
3898 // | 3880 // |
3899 // TODO(ager): We should recognize when the prototype chains for different | 3881 // TODO(ager): We should recognize when the prototype chains for different |
3900 // maps are identical. In that case we can avoid repeatedly generating the | 3882 // maps are identical. In that case we can avoid repeatedly generating the |
3901 // same prototype map checks. | 3883 // same prototype map checks. |
3902 for (int i = 0; i < number_of_types; ++i) { | 3884 for (int i = 0; i < number_of_types; ++i) { |
3903 Handle<Map> map = types->at(i); | 3885 Handle<Map> map = types->at(i); |
3904 if (expr->ComputeTarget(map, name)) { | 3886 if (expr->ComputeTarget(map, name)) { |
3905 maps.Add(map); | |
3906 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3887 HSubgraph* subgraph = CreateBranchSubgraph(environment()); |
3907 SubgraphScope scope(this, subgraph); | 3888 SubgraphScope scope(this, subgraph); |
3908 AddCheckConstantFunction(expr, receiver, map, false); | 3889 AddCheckConstantFunction(expr, receiver, map, false); |
3909 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 3890 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
3910 PrintF("Trying to inline the polymorphic call to %s\n", | 3891 PrintF("Trying to inline the polymorphic call to %s\n", |
3911 *name->ToCString()); | 3892 *name->ToCString()); |
3912 } | 3893 } |
3913 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { | 3894 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { |
3914 // Check for bailout, as trying to inline might fail due to bailout | 3895 // Check for bailout, as trying to inline might fail due to bailout |
3915 // during hydrogen processing. | 3896 // during hydrogen processing. |
3916 CHECK_BAILOUT; | 3897 CHECK_BAILOUT; |
3917 HCall* call = new HCallConstantFunction(expr->target(), argument_count); | 3898 HCall* call = new HCallConstantFunction(expr->target(), argument_count); |
3918 call->set_position(expr->position()); | 3899 call->set_position(expr->position()); |
3919 PreProcessCall(call); | 3900 PreProcessCall(call); |
3920 PushAndAdd(call); | 3901 PushAndAdd(call); |
3921 } | 3902 } |
| 3903 maps.Add(map); |
3922 subgraphs.Add(subgraph); | 3904 subgraphs.Add(subgraph); |
3923 } else { | 3905 } else { |
3924 needs_generic = true; | 3906 needs_generic = true; |
3925 } | 3907 } |
3926 } | 3908 } |
3927 | 3909 |
3928 // If we couldn't compute the target for any of the maps just perform an | 3910 // If we couldn't compute the target for any of the maps just perform an |
3929 // IC call. | 3911 // IC call. |
3930 if (maps.length() == 0) { | 3912 if (maps.length() == 0) { |
3931 HContext* context = new HContext; | 3913 HContext* context = new HContext; |
3932 AddInstruction(context); | 3914 AddInstruction(context); |
3933 HCall* call = new HCallNamed(context, name, argument_count); | 3915 HCall* call = new HCallNamed(context, name, argument_count); |
3934 call->set_position(expr->position()); | 3916 call->set_position(expr->position()); |
3935 PreProcessCall(call); | 3917 PreProcessCall(call); |
3936 ast_context()->ReturnInstruction(call, expr->id()); | 3918 ast_context()->ReturnInstruction(call, expr->id()); |
3937 } else { | 3919 } else { |
3938 // Build subgraph for generic call through IC. | 3920 // Build subgraph for generic call through IC. |
3939 { | 3921 HSubgraph* default_graph = CreateBranchSubgraph(environment()); |
3940 HSubgraph* subgraph = CreateBranchSubgraph(environment()); | 3922 { SubgraphScope scope(this, default_graph); |
3941 SubgraphScope scope(this, subgraph); | |
3942 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { | 3923 if (!needs_generic && FLAG_deoptimize_uncommon_cases) { |
3943 subgraph->FinishExit(new HDeoptimize()); | 3924 default_graph->FinishExit(new HDeoptimize()); |
3944 } else { | 3925 } else { |
3945 HContext* context = new HContext; | 3926 HContext* context = new HContext; |
3946 AddInstruction(context); | 3927 AddInstruction(context); |
3947 HCall* call = new HCallNamed(context, name, argument_count); | 3928 HCall* call = new HCallNamed(context, name, argument_count); |
3948 call->set_position(expr->position()); | 3929 call->set_position(expr->position()); |
3949 PreProcessCall(call); | 3930 PreProcessCall(call); |
3950 PushAndAdd(call); | 3931 PushAndAdd(call); |
3951 } | 3932 } |
3952 subgraphs.Add(subgraph); | |
3953 } | 3933 } |
3954 | 3934 |
3955 HBasicBlock* new_exit_block = | 3935 HBasicBlock* new_exit_block = |
3956 BuildTypeSwitch(&maps, &subgraphs, receiver, expr->id()); | 3936 BuildTypeSwitch(receiver, &maps, &subgraphs, default_graph, expr->id()); |
3957 subgraph()->set_exit_block(new_exit_block); | 3937 subgraph()->set_exit_block(new_exit_block); |
3958 // In an effect context, we did not materialized the value in the | 3938 // In an effect context, we did not materialized the value in the |
3959 // predecessor environments so there's no need to handle it here. | 3939 // predecessor environments so there's no need to handle it here. |
3960 if (new_exit_block != NULL && !ast_context()->IsEffect()) { | 3940 if (new_exit_block != NULL && !ast_context()->IsEffect()) { |
3961 ast_context()->ReturnValue(Pop()); | 3941 ast_context()->ReturnValue(Pop()); |
3962 } | 3942 } |
3963 } | 3943 } |
3964 } | 3944 } |
3965 | 3945 |
3966 | 3946 |
(...skipping 2025 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5992 } | 5972 } |
5993 } | 5973 } |
5994 | 5974 |
5995 #ifdef DEBUG | 5975 #ifdef DEBUG |
5996 if (graph_ != NULL) graph_->Verify(); | 5976 if (graph_ != NULL) graph_->Verify(); |
5997 if (allocator_ != NULL) allocator_->Verify(); | 5977 if (allocator_ != NULL) allocator_->Verify(); |
5998 #endif | 5978 #endif |
5999 } | 5979 } |
6000 | 5980 |
6001 } } // namespace v8::internal | 5981 } } // namespace v8::internal |
OLD | NEW |