OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 5026 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5037 | 5037 |
5038 instr->set_position(expr->position()); | 5038 instr->set_position(expr->position()); |
5039 return ast_context()->ReturnInstruction(instr, expr->id()); | 5039 return ast_context()->ReturnInstruction(instr, expr->id()); |
5040 } | 5040 } |
5041 | 5041 |
5042 | 5042 |
5043 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( | 5043 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( |
5044 int position, | 5044 int position, |
5045 BailoutId assignment_id, | 5045 BailoutId assignment_id, |
5046 HValue* object, | 5046 HValue* object, |
5047 HValue* store_value, | 5047 HValue* value, |
5048 HValue* result_value, | |
5049 SmallMapList* types, | 5048 SmallMapList* types, |
5050 Handle<String> name) { | 5049 Handle<String> name) { |
5051 // Use monomorphic store if property lookup results in the same field index | 5050 // Use monomorphic store if property lookup results in the same field index |
5052 // for all maps. Requires special map check on the set of all handled maps. | 5051 // for all maps. Requires special map check on the set of all handled maps. |
5053 if (types->length() > kMaxStorePolymorphism) return false; | 5052 if (types->length() > kMaxStorePolymorphism) return false; |
5054 | 5053 |
5055 // TODO(verwaest): Merge the checking logic with the code in | 5054 // TODO(verwaest): Merge the checking logic with the code in |
5056 // TryLoadPolymorphicAsMonomorphic. | 5055 // TryLoadPolymorphicAsMonomorphic. |
5057 LookupResult lookup(isolate()); | 5056 LookupResult lookup(isolate()); |
5058 int count; | 5057 int count; |
(...skipping 25 matching lines...) Expand all Loading... |
5084 } | 5083 } |
5085 | 5084 |
5086 if (count != types->length()) return false; | 5085 if (count != types->length()) return false; |
5087 | 5086 |
5088 // Everything matched; can use monomorphic store. | 5087 // Everything matched; can use monomorphic store. |
5089 BuildCheckHeapObject(object); | 5088 BuildCheckHeapObject(object); |
5090 AddInstruction(HCheckMaps::New(object, types, zone())); | 5089 AddInstruction(HCheckMaps::New(object, types, zone())); |
5091 HInstruction* store; | 5090 HInstruction* store; |
5092 CHECK_ALIVE_OR_RETURN( | 5091 CHECK_ALIVE_OR_RETURN( |
5093 store = BuildStoreNamedField( | 5092 store = BuildStoreNamedField( |
5094 object, name, store_value, types->at(count - 1), &lookup), | 5093 object, name, value, types->at(count - 1), &lookup), |
5095 true); | 5094 true); |
5096 if (result_value != NULL) Push(result_value); | 5095 Push(value); |
5097 Push(store_value); | |
5098 store->set_position(position); | 5096 store->set_position(position); |
5099 AddInstruction(store); | 5097 AddInstruction(store); |
5100 AddSimulate(assignment_id); | 5098 AddSimulate(assignment_id); |
5101 if (result_value != NULL) Drop(1); | |
5102 ast_context()->ReturnValue(Pop()); | 5099 ast_context()->ReturnValue(Pop()); |
5103 return true; | 5100 return true; |
5104 } | 5101 } |
5105 | 5102 |
5106 | 5103 |
5107 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( | 5104 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( |
5108 BailoutId id, | 5105 BailoutId id, |
5109 int position, | 5106 int position, |
5110 BailoutId assignment_id, | 5107 BailoutId assignment_id, |
5111 HValue* object, | 5108 HValue* object, |
5112 HValue* store_value, | 5109 HValue* value, |
5113 HValue* result_value, | |
5114 SmallMapList* types, | 5110 SmallMapList* types, |
5115 Handle<String> name) { | 5111 Handle<String> name) { |
5116 if (TryStorePolymorphicAsMonomorphic( | 5112 if (TryStorePolymorphicAsMonomorphic( |
5117 position, assignment_id, object, | 5113 position, assignment_id, object, value, types, name)) { |
5118 store_value, result_value, types, name)) { | |
5119 return; | 5114 return; |
5120 } | 5115 } |
5121 | 5116 |
5122 // TODO(ager): We should recognize when the prototype chains for different | 5117 // TODO(ager): We should recognize when the prototype chains for different |
5123 // maps are identical. In that case we can avoid repeatedly generating the | 5118 // maps are identical. In that case we can avoid repeatedly generating the |
5124 // same prototype map checks. | 5119 // same prototype map checks. |
5125 int count = 0; | 5120 int count = 0; |
5126 HBasicBlock* join = NULL; | 5121 HBasicBlock* join = NULL; |
5127 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 5122 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
5128 Handle<Map> map = types->at(i); | 5123 Handle<Map> map = types->at(i); |
5129 LookupResult lookup(isolate()); | 5124 LookupResult lookup(isolate()); |
5130 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 5125 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
5131 if (count == 0) { | 5126 if (count == 0) { |
5132 BuildCheckHeapObject(object); | 5127 BuildCheckHeapObject(object); |
5133 join = graph()->CreateBasicBlock(); | 5128 join = graph()->CreateBasicBlock(); |
5134 } | 5129 } |
5135 ++count; | 5130 ++count; |
5136 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5131 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
5137 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5132 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
5138 HCompareMap* compare = | 5133 HCompareMap* compare = |
5139 new(zone()) HCompareMap(object, map, if_true, if_false); | 5134 new(zone()) HCompareMap(object, map, if_true, if_false); |
5140 current_block()->Finish(compare); | 5135 current_block()->Finish(compare); |
5141 | 5136 |
5142 set_current_block(if_true); | 5137 set_current_block(if_true); |
5143 HInstruction* instr; | 5138 HInstruction* instr; |
5144 CHECK_ALIVE(instr = BuildStoreNamedField( | 5139 CHECK_ALIVE( |
5145 object, name, store_value, map, &lookup)); | 5140 instr = BuildStoreNamedField(object, name, value, map, &lookup)); |
5146 instr->set_position(position); | 5141 instr->set_position(position); |
5147 // Goto will add the HSimulate for the store. | 5142 // Goto will add the HSimulate for the store. |
5148 AddInstruction(instr); | 5143 AddInstruction(instr); |
5149 if (!ast_context()->IsEffect()) { | 5144 if (!ast_context()->IsEffect()) Push(value); |
5150 if (result_value != NULL) Push(result_value); | |
5151 Push(store_value); | |
5152 } | |
5153 current_block()->Goto(join); | 5145 current_block()->Goto(join); |
5154 | 5146 |
5155 set_current_block(if_false); | 5147 set_current_block(if_false); |
5156 } | 5148 } |
5157 } | 5149 } |
5158 | 5150 |
5159 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5151 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
5160 // know about and do not want to handle ones we've never seen. Otherwise | 5152 // know about and do not want to handle ones we've never seen. Otherwise |
5161 // use a generic IC. | 5153 // use a generic IC. |
5162 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5154 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
5163 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); | 5155 current_block()->FinishExitWithDeoptimization(HDeoptimize::kNoUses); |
5164 } else { | 5156 } else { |
5165 HInstruction* instr = BuildStoreNamedGeneric(object, name, store_value); | 5157 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); |
5166 instr->set_position(position); | 5158 instr->set_position(position); |
5167 AddInstruction(instr); | 5159 AddInstruction(instr); |
5168 | 5160 |
5169 if (join != NULL) { | 5161 if (join != NULL) { |
5170 if (!ast_context()->IsEffect()) { | 5162 if (!ast_context()->IsEffect()) Push(value); |
5171 if (result_value != NULL) Push(result_value); | |
5172 Push(store_value); | |
5173 } | |
5174 current_block()->Goto(join); | 5163 current_block()->Goto(join); |
5175 } else { | 5164 } else { |
5176 // The HSimulate for the store should not see the stored value in | 5165 // The HSimulate for the store should not see the stored value in |
5177 // effect contexts (it is not materialized at expr->id() in the | 5166 // effect contexts (it is not materialized at expr->id() in the |
5178 // unoptimized code). | 5167 // unoptimized code). |
5179 if (instr->HasObservableSideEffects()) { | 5168 if (instr->HasObservableSideEffects()) { |
5180 if (ast_context()->IsEffect()) { | 5169 if (ast_context()->IsEffect()) { |
5181 AddSimulate(id, REMOVABLE_SIMULATE); | 5170 AddSimulate(id, REMOVABLE_SIMULATE); |
5182 } else { | 5171 } else { |
5183 if (result_value != NULL) Push(result_value); | 5172 Push(value); |
5184 Push(store_value); | |
5185 AddSimulate(id, REMOVABLE_SIMULATE); | 5173 AddSimulate(id, REMOVABLE_SIMULATE); |
5186 Drop(result_value != NULL ? 2 : 1); | 5174 Drop(1); |
5187 } | 5175 } |
5188 } | 5176 } |
5189 return ast_context()->ReturnValue( | 5177 return ast_context()->ReturnValue(value); |
5190 result_value != NULL ? result_value : store_value); | |
5191 } | 5178 } |
5192 } | 5179 } |
5193 | 5180 |
5194 ASSERT(join != NULL); | 5181 ASSERT(join != NULL); |
5195 join->SetJoinId(id); | 5182 join->SetJoinId(id); |
5196 set_current_block(join); | 5183 set_current_block(join); |
5197 if (!ast_context()->IsEffect()) { | 5184 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
5198 if (result_value != NULL) Drop(1); | |
5199 ast_context()->ReturnValue(Pop()); | |
5200 } | |
5201 } | 5185 } |
5202 | 5186 |
5203 | 5187 |
5204 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { | 5188 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { |
5205 Property* prop = expr->target()->AsProperty(); | 5189 Property* prop = expr->target()->AsProperty(); |
5206 ASSERT(prop != NULL); | 5190 ASSERT(prop != NULL); |
5207 CHECK_ALIVE(VisitForValue(prop->obj())); | 5191 CHECK_ALIVE(VisitForValue(prop->obj())); |
5208 | 5192 |
5209 if (prop->key()->IsPropertyName()) { | 5193 if (prop->key()->IsPropertyName()) { |
5210 // Named store. | 5194 // Named store. |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5279 } | 5263 } |
5280 } | 5264 } |
5281 | 5265 |
5282 | 5266 |
5283 void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, | 5267 void HOptimizedGraphBuilder::BuildStoreNamed(Expression* expr, |
5284 BailoutId id, | 5268 BailoutId id, |
5285 int position, | 5269 int position, |
5286 BailoutId assignment_id, | 5270 BailoutId assignment_id, |
5287 Property* prop, | 5271 Property* prop, |
5288 HValue* object, | 5272 HValue* object, |
5289 HValue* store_value, | 5273 HValue* value) { |
5290 HValue* result_value) { | |
5291 Literal* key = prop->key()->AsLiteral(); | 5274 Literal* key = prop->key()->AsLiteral(); |
5292 Handle<String> name = Handle<String>::cast(key->value()); | 5275 Handle<String> name = Handle<String>::cast(key->value()); |
5293 ASSERT(!name.is_null()); | 5276 ASSERT(!name.is_null()); |
5294 | 5277 |
5295 HInstruction* instr = NULL; | 5278 HInstruction* instr = NULL; |
5296 SmallMapList* types = expr->GetReceiverTypes(); | 5279 SmallMapList* types = expr->GetReceiverTypes(); |
5297 bool monomorphic = expr->IsMonomorphic(); | 5280 bool monomorphic = expr->IsMonomorphic(); |
5298 Handle<Map> map; | 5281 Handle<Map> map; |
5299 if (monomorphic) { | 5282 if (monomorphic) { |
5300 map = types->first(); | 5283 map = types->first(); |
5301 if (map->is_dictionary_map()) monomorphic = false; | 5284 if (map->is_dictionary_map()) monomorphic = false; |
5302 } | 5285 } |
5303 if (monomorphic) { | 5286 if (monomorphic) { |
5304 Handle<JSFunction> setter; | 5287 Handle<JSFunction> setter; |
5305 Handle<JSObject> holder; | 5288 Handle<JSObject> holder; |
5306 if (LookupSetter(map, name, &setter, &holder)) { | 5289 if (LookupSetter(map, name, &setter, &holder)) { |
5307 AddCheckConstantFunction(holder, object, map); | 5290 AddCheckConstantFunction(holder, object, map); |
5308 // Don't try to inline if the result_value is different from the | 5291 if (FLAG_inline_accessors && |
5309 // store_value. That case isn't handled yet by the inlining. | 5292 TryInlineSetter(setter, id, assignment_id, value)) { |
5310 if (result_value == NULL && | |
5311 FLAG_inline_accessors && | |
5312 TryInlineSetter(setter, id, assignment_id, store_value)) { | |
5313 return; | 5293 return; |
5314 } | 5294 } |
5315 Drop(2); | 5295 Drop(2); |
5316 Add<HPushArgument>(object); | 5296 Add<HPushArgument>(object); |
5317 Add<HPushArgument>(store_value); | 5297 Add<HPushArgument>(value); |
5318 instr = new(zone()) HCallConstantFunction(setter, 2); | 5298 instr = new(zone()) HCallConstantFunction(setter, 2); |
5319 } else { | 5299 } else { |
5320 Drop(2); | 5300 Drop(2); |
5321 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 5301 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
5322 name, | 5302 name, |
5323 store_value, | 5303 value, |
5324 map)); | 5304 map)); |
5325 } | 5305 } |
| 5306 |
5326 } else if (types != NULL && types->length() > 1) { | 5307 } else if (types != NULL && types->length() > 1) { |
5327 Drop(2); | 5308 Drop(2); |
5328 return HandlePolymorphicStoreNamedField( | 5309 return HandlePolymorphicStoreNamedField( |
5329 id, position, assignment_id, object, | 5310 id, position, assignment_id, object, value, types, name); |
5330 store_value, result_value, types, name); | |
5331 } else { | 5311 } else { |
5332 Drop(2); | 5312 Drop(2); |
5333 instr = BuildStoreNamedGeneric(object, name, store_value); | 5313 instr = BuildStoreNamedGeneric(object, name, value); |
5334 } | 5314 } |
5335 | 5315 |
5336 if (result_value != NULL) Push(result_value); | 5316 Push(value); |
5337 Push(store_value); | |
5338 instr->set_position(position); | 5317 instr->set_position(position); |
5339 AddInstruction(instr); | 5318 AddInstruction(instr); |
5340 if (instr->HasObservableSideEffects()) { | 5319 if (instr->HasObservableSideEffects()) { |
5341 AddSimulate(assignment_id, REMOVABLE_SIMULATE); | 5320 AddSimulate(assignment_id, REMOVABLE_SIMULATE); |
5342 } | 5321 } |
5343 if (result_value != NULL) Drop(1); | |
5344 return ast_context()->ReturnValue(Pop()); | 5322 return ast_context()->ReturnValue(Pop()); |
5345 } | 5323 } |
5346 | 5324 |
5347 | 5325 |
5348 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { | 5326 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { |
5349 Expression* target = expr->target(); | 5327 Expression* target = expr->target(); |
5350 VariableProxy* proxy = target->AsVariableProxy(); | 5328 VariableProxy* proxy = target->AsVariableProxy(); |
5351 Property* prop = target->AsProperty(); | 5329 Property* prop = target->AsProperty(); |
5352 ASSERT(proxy == NULL || prop == NULL); | 5330 ASSERT(proxy == NULL || prop == NULL); |
5353 | 5331 |
(...skipping 2544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7898 } else if (types != NULL && types->length() > 1) { | 7876 } else if (types != NULL && types->length() > 1) { |
7899 load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); | 7877 load = TryLoadPolymorphicAsMonomorphic(prop, object, types, name); |
7900 } | 7878 } |
7901 if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); | 7879 if (load == NULL) load = BuildLoadNamedGeneric(object, name, prop); |
7902 PushAndAdd(load); | 7880 PushAndAdd(load); |
7903 if (load->HasObservableSideEffects()) { | 7881 if (load->HasObservableSideEffects()) { |
7904 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); | 7882 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
7905 } | 7883 } |
7906 | 7884 |
7907 after = BuildIncrement(returns_original_input, expr); | 7885 after = BuildIncrement(returns_original_input, expr); |
| 7886 input = Pop(); |
7908 | 7887 |
7909 HValue* result = returns_original_input ? Pop() : NULL; | 7888 HInstruction* store; |
| 7889 if (!monomorphic || map->is_observed()) { |
| 7890 // If we don't know the monomorphic type, do a generic store. |
| 7891 CHECK_ALIVE(store = BuildStoreNamedGeneric(object, name, after)); |
| 7892 } else { |
| 7893 Handle<JSFunction> setter; |
| 7894 Handle<JSObject> holder; |
| 7895 if (LookupSetter(map, name, &setter, &holder)) { |
| 7896 store = BuildCallSetter(object, after, map, setter, holder); |
| 7897 } else { |
| 7898 CHECK_ALIVE(store = BuildStoreNamedMonomorphic(object, |
| 7899 name, |
| 7900 after, |
| 7901 map)); |
| 7902 } |
| 7903 } |
| 7904 AddInstruction(store); |
7910 | 7905 |
7911 return BuildStoreNamed(prop, expr->id(), expr->position(), | 7906 // Overwrite the receiver in the bailout environment with the result |
7912 expr->AssignmentId(), prop, object, after, result); | 7907 // of the operation, and the placeholder with the original value if |
| 7908 // necessary. |
| 7909 environment()->SetExpressionStackAt(0, after); |
| 7910 if (returns_original_input) environment()->SetExpressionStackAt(1, input); |
| 7911 if (store->HasObservableSideEffects()) { |
| 7912 AddSimulate(expr->AssignmentId(), REMOVABLE_SIMULATE); |
| 7913 } |
| 7914 |
7913 } else { | 7915 } else { |
7914 // Keyed property. | 7916 // Keyed property. |
7915 if (returns_original_input) Push(graph()->GetConstantUndefined()); | 7917 if (returns_original_input) Push(graph()->GetConstantUndefined()); |
7916 | 7918 |
7917 CHECK_ALIVE(VisitForValue(prop->obj())); | 7919 CHECK_ALIVE(VisitForValue(prop->obj())); |
7918 CHECK_ALIVE(VisitForValue(prop->key())); | 7920 CHECK_ALIVE(VisitForValue(prop->key())); |
7919 HValue* obj = environment()->ExpressionStackAt(1); | 7921 HValue* obj = environment()->ExpressionStackAt(1); |
7920 HValue* key = environment()->ExpressionStackAt(0); | 7922 HValue* key = environment()->ExpressionStackAt(0); |
7921 | 7923 |
7922 bool has_side_effects = false; | 7924 bool has_side_effects = false; |
(...skipping 2251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10174 if (ShouldProduceTraceOutput()) { | 10176 if (ShouldProduceTraceOutput()) { |
10175 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10177 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10176 } | 10178 } |
10177 | 10179 |
10178 #ifdef DEBUG | 10180 #ifdef DEBUG |
10179 graph_->Verify(false); // No full verify. | 10181 graph_->Verify(false); // No full verify. |
10180 #endif | 10182 #endif |
10181 } | 10183 } |
10182 | 10184 |
10183 } } // namespace v8::internal | 10185 } } // namespace v8::internal |
OLD | NEW |