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 4910 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4921 static bool CanInlinePropertyAccess(Type* type) { | 4921 static bool CanInlinePropertyAccess(Type* type) { |
4922 if (type->Is(Type::NumberOrString())) return true; | 4922 if (type->Is(Type::NumberOrString())) return true; |
4923 if (!type->IsClass()) return false; | 4923 if (!type->IsClass()) return false; |
4924 Handle<Map> map = type->AsClass(); | 4924 Handle<Map> map = type->AsClass(); |
4925 return map->IsJSObjectMap() && | 4925 return map->IsJSObjectMap() && |
4926 !map->is_dictionary_map() && | 4926 !map->is_dictionary_map() && |
4927 !map->has_named_interceptor(); | 4927 !map->has_named_interceptor(); |
4928 } | 4928 } |
4929 | 4929 |
4930 | 4930 |
4931 static void LookupInPrototypes(Handle<Map> map, | |
4932 Handle<String> name, | |
4933 LookupResult* lookup, | |
4934 Zone* zone) { | |
4935 while (map->prototype()->IsJSObject()) { | |
4936 Handle<JSObject> holder(JSObject::cast(map->prototype())); | |
4937 map = handle(holder->map()); | |
4938 if (!CanInlinePropertyAccess(IC::MapToType<Type>(map, zone))) break; | |
4939 map->LookupDescriptor(*holder, *name, lookup); | |
4940 if (lookup->IsFound()) return; | |
4941 } | |
4942 lookup->NotFound(); | |
4943 } | |
4944 | |
4945 | |
4946 // Tries to find a JavaScript accessor of the given name in the prototype chain | |
4947 // starting at the given map. Return true iff there is one, including the | |
4948 // corresponding AccessorPair plus its holder (which could be null when the | |
4949 // accessor is found directly in the given map). | |
4950 static bool LookupAccessorPair(Handle<Map> map, | |
4951 Handle<String> name, | |
4952 Handle<AccessorPair>* accessors, | |
4953 Handle<JSObject>* holder, | |
4954 Zone* zone) { | |
4955 Isolate* isolate = map->GetIsolate(); | |
4956 LookupResult lookup(isolate); | |
4957 | |
4958 // Check for a JavaScript accessor directly in the map. | |
4959 map->LookupDescriptor(NULL, *name, &lookup); | |
4960 if (lookup.IsPropertyCallbacks()) { | |
4961 Handle<Object> callback(lookup.GetValueFromMap(*map), isolate); | |
4962 if (!callback->IsAccessorPair()) return false; | |
4963 *accessors = Handle<AccessorPair>::cast(callback); | |
4964 *holder = Handle<JSObject>(); | |
4965 return true; | |
4966 } | |
4967 | |
4968 // Everything else, e.g. a field, can't be an accessor call. | |
4969 if (lookup.IsFound()) return false; | |
4970 | |
4971 // Check for a JavaScript accessor somewhere in the proto chain. | |
4972 LookupInPrototypes(map, name, &lookup, zone); | |
4973 if (lookup.IsPropertyCallbacks()) { | |
4974 Handle<Object> callback(lookup.GetValue(), isolate); | |
4975 if (!callback->IsAccessorPair()) return false; | |
4976 *accessors = Handle<AccessorPair>::cast(callback); | |
4977 *holder = Handle<JSObject>(lookup.holder()); | |
4978 return true; | |
4979 } | |
4980 | |
4981 // We haven't found a JavaScript accessor anywhere. | |
4982 return false; | |
4983 } | |
4984 | |
4985 | |
4986 static bool LookupSetter(Handle<Map> map, | |
4987 Handle<String> name, | |
4988 Handle<JSFunction>* setter, | |
4989 Handle<JSObject>* holder, | |
4990 Zone* zone) { | |
4991 Handle<AccessorPair> accessors; | |
4992 if (LookupAccessorPair(map, name, &accessors, holder, zone) && | |
4993 accessors->setter()->IsJSFunction()) { | |
4994 Handle<JSFunction> func(JSFunction::cast(accessors->setter())); | |
4995 CallOptimization call_optimization(func); | |
4996 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | |
4997 if (call_optimization.is_simple_api_call()) return false; | |
4998 *setter = func; | |
4999 return true; | |
5000 } | |
5001 return false; | |
5002 } | |
5003 | |
5004 | |
5005 // Determines whether the given array or object literal boilerplate satisfies | 4931 // Determines whether the given array or object literal boilerplate satisfies |
5006 // all limits to be considered for fast deep-copying and computes the total | 4932 // all limits to be considered for fast deep-copying and computes the total |
5007 // size of all objects that are part of the graph. | 4933 // size of all objects that are part of the graph. |
5008 static bool IsFastLiteral(Handle<JSObject> boilerplate, | 4934 static bool IsFastLiteral(Handle<JSObject> boilerplate, |
5009 int max_depth, | 4935 int max_depth, |
5010 int* max_properties) { | 4936 int* max_properties) { |
5011 if (boilerplate->map()->is_deprecated()) { | 4937 if (boilerplate->map()->is_deprecated()) { |
5012 Handle<Object> result = JSObject::TryMigrateInstance(boilerplate); | 4938 Handle<Object> result = JSObject::TryMigrateInstance(boilerplate); |
5013 if (result.is_null()) return false; | 4939 if (result.is_null()) return false; |
5014 } | 4940 } |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5140 if (property->emit_store()) { | 5066 if (property->emit_store()) { |
5141 CHECK_ALIVE(VisitForValue(value)); | 5067 CHECK_ALIVE(VisitForValue(value)); |
5142 HValue* value = Pop(); | 5068 HValue* value = Pop(); |
5143 Handle<Map> map = property->GetReceiverType(); | 5069 Handle<Map> map = property->GetReceiverType(); |
5144 Handle<String> name = property->key()->AsPropertyName(); | 5070 Handle<String> name = property->key()->AsPropertyName(); |
5145 HInstruction* store; | 5071 HInstruction* store; |
5146 if (map.is_null()) { | 5072 if (map.is_null()) { |
5147 // If we don't know the monomorphic type, do a generic store. | 5073 // If we don't know the monomorphic type, do a generic store. |
5148 CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value)); | 5074 CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value)); |
5149 } else { | 5075 } else { |
5150 #if DEBUG | 5076 PropertyAccessInfo info(this, STORE, ToType(map), name); |
5151 Handle<JSFunction> setter; | 5077 if (info.CanAccessMonomorphic()) { |
5152 Handle<JSObject> holder; | 5078 HValue* checked_literal = BuildCheckMap(literal, map); |
5153 ASSERT(!LookupSetter(map, name, &setter, &holder, zone())); | 5079 ASSERT(!info.lookup()->IsPropertyCallbacks()); |
5154 #endif | 5080 store = BuildStoreMonomorphic( |
5155 CHECK_ALIVE(store = BuildStoreNamedMonomorphic(literal, | 5081 &info, checked_literal, value, |
5156 name, | 5082 BailoutId::None(), BailoutId::None()); |
5157 value, | 5083 } else { |
5158 map)); | 5084 CHECK_ALIVE( |
| 5085 store = BuildStoreNamedGeneric(literal, name, value)); |
| 5086 } |
5159 } | 5087 } |
5160 AddInstruction(store); | 5088 AddInstruction(store); |
5161 if (store->HasObservableSideEffects()) { | 5089 if (store->HasObservableSideEffects()) { |
5162 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); | 5090 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); |
5163 } | 5091 } |
5164 } else { | 5092 } else { |
5165 CHECK_ALIVE(VisitForEffect(value)); | 5093 CHECK_ALIVE(VisitForEffect(value)); |
5166 } | 5094 } |
5167 break; | 5095 break; |
5168 } | 5096 } |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5324 | 5252 |
5325 | 5253 |
5326 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, | 5254 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, |
5327 Handle<Map> map) { | 5255 Handle<Map> map) { |
5328 BuildCheckHeapObject(object); | 5256 BuildCheckHeapObject(object); |
5329 return Add<HCheckMaps>(object, map, top_info()); | 5257 return Add<HCheckMaps>(object, map, top_info()); |
5330 } | 5258 } |
5331 | 5259 |
5332 | 5260 |
5333 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( | 5261 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( |
| 5262 PropertyAccessInfo* info, |
5334 HValue* checked_object, | 5263 HValue* checked_object, |
5335 Handle<String> name, | 5264 HValue* value) { |
5336 HValue* value, | 5265 bool transition_to_field = info->lookup()->IsTransition(); |
5337 Handle<Map> map, | 5266 // TODO(verwaest): Move this logic into PropertyAccessInfo. |
5338 LookupResult* lookup) { | 5267 HObjectAccess field_access = HObjectAccess::ForField( |
5339 ASSERT(lookup->IsFound()); | 5268 info->map(), info->lookup(), info->name()); |
5340 // If the property does not exist yet, we have to check that it wasn't made | |
5341 // readonly or turned into a setter by some meanwhile modifications on the | |
5342 // prototype chain. | |
5343 if (!lookup->IsProperty() && map->prototype()->IsJSReceiver()) { | |
5344 Object* proto = map->prototype(); | |
5345 // First check that the prototype chain isn't affected already. | |
5346 LookupResult proto_result(isolate()); | |
5347 proto->Lookup(*name, &proto_result); | |
5348 if (proto_result.IsProperty()) { | |
5349 // If the inherited property could induce readonly-ness, bail out. | |
5350 if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) { | |
5351 Bailout(kImproperObjectOnPrototypeChainForStore); | |
5352 return NULL; | |
5353 } | |
5354 // We only need to check up to the preexisting property. | |
5355 proto = proto_result.holder(); | |
5356 } else { | |
5357 // Otherwise, find the top prototype. | |
5358 while (proto->GetPrototype(isolate())->IsJSObject()) { | |
5359 proto = proto->GetPrototype(isolate()); | |
5360 } | |
5361 ASSERT(proto->GetPrototype(isolate())->IsNull()); | |
5362 } | |
5363 ASSERT(proto->IsJSObject()); | |
5364 BuildCheckPrototypeMaps( | |
5365 Handle<JSObject>(JSObject::cast(map->prototype())), | |
5366 Handle<JSObject>(JSObject::cast(proto))); | |
5367 } | |
5368 | |
5369 HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name); | |
5370 bool transition_to_field = lookup->IsTransitionToField(*map); | |
5371 | 5269 |
5372 HStoreNamedField *instr; | 5270 HStoreNamedField *instr; |
5373 if (FLAG_track_double_fields && field_access.representation().IsDouble()) { | 5271 if (FLAG_track_double_fields && field_access.representation().IsDouble()) { |
5374 HObjectAccess heap_number_access = | 5272 HObjectAccess heap_number_access = |
5375 field_access.WithRepresentation(Representation::Tagged()); | 5273 field_access.WithRepresentation(Representation::Tagged()); |
5376 if (transition_to_field) { | 5274 if (transition_to_field) { |
5377 // The store requires a mutable HeapNumber to be allocated. | 5275 // The store requires a mutable HeapNumber to be allocated. |
5378 NoObservableSideEffectsScope no_side_effects(this); | 5276 NoObservableSideEffectsScope no_side_effects(this); |
5379 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); | 5277 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); |
5380 | 5278 |
(...skipping 20 matching lines...) Expand all Loading... |
5401 value, STORE_TO_INITIALIZED_ENTRY); | 5299 value, STORE_TO_INITIALIZED_ENTRY); |
5402 } | 5300 } |
5403 } else { | 5301 } else { |
5404 // This is a normal store. | 5302 // This is a normal store. |
5405 instr = New<HStoreNamedField>( | 5303 instr = New<HStoreNamedField>( |
5406 checked_object->ActualValue(), field_access, value, | 5304 checked_object->ActualValue(), field_access, value, |
5407 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); | 5305 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); |
5408 } | 5306 } |
5409 | 5307 |
5410 if (transition_to_field) { | 5308 if (transition_to_field) { |
5411 Handle<Map> transition(lookup->GetTransitionMapFromMap(*map)); | 5309 HConstant* transition_constant = Add<HConstant>(info->transition()); |
5412 HConstant* transition_constant = Add<HConstant>(transition); | |
5413 instr->SetTransition(transition_constant, top_info()); | 5310 instr->SetTransition(transition_constant, top_info()); |
5414 // TODO(fschneider): Record the new map type of the object in the IR to | |
5415 // enable elimination of redundant checks after the transition store. | |
5416 instr->SetGVNFlag(kChangesMaps); | 5311 instr->SetGVNFlag(kChangesMaps); |
5417 } | 5312 } |
5418 return instr; | 5313 return instr; |
5419 } | 5314 } |
5420 | 5315 |
5421 | 5316 |
5422 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric( | 5317 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric( |
5423 HValue* object, | 5318 HValue* object, |
5424 Handle<String> name, | 5319 Handle<String> name, |
5425 HValue* value) { | 5320 HValue* value, |
| 5321 bool is_uninitialized) { |
| 5322 if (is_uninitialized) { |
| 5323 Add<HDeoptimize>("Insufficient type feedback for property assignment", |
| 5324 Deoptimizer::SOFT); |
| 5325 } |
| 5326 |
5426 return New<HStoreNamedGeneric>( | 5327 return New<HStoreNamedGeneric>( |
5427 object, | 5328 object, |
5428 name, | 5329 name, |
5429 value, | 5330 value, |
5430 function_strict_mode_flag()); | 5331 function_strict_mode_flag()); |
5431 } | 5332 } |
5432 | 5333 |
5433 | 5334 |
5434 // Sets the lookup result and returns true if the load/store can be inlined. | 5335 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( |
5435 static bool ComputeStoreField(Type* type, | |
5436 Handle<String> name, | |
5437 LookupResult* lookup, | |
5438 bool lookup_transition = true) { | |
5439 if (!CanInlinePropertyAccess(type) || !type->IsClass()) { | |
5440 lookup->NotFound(); | |
5441 return false; | |
5442 } | |
5443 Handle<Map> map = type->AsClass(); | |
5444 ASSERT(!map->is_observed()); | |
5445 // If we directly find a field, the access can be inlined. | |
5446 map->LookupDescriptor(NULL, *name, lookup); | |
5447 if (lookup->IsField()) return true; | |
5448 | |
5449 if (!lookup_transition) return false; | |
5450 | |
5451 map->LookupTransition(NULL, *name, lookup); | |
5452 return lookup->IsTransitionToField(*map) && map->unused_property_fields() > 0; | |
5453 } | |
5454 | |
5455 | |
5456 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( | |
5457 HValue* object, | |
5458 Handle<String> name, | |
5459 HValue* value, | |
5460 Handle<Map> map) { | |
5461 // Handle a store to a known field. | |
5462 LookupResult lookup(isolate()); | |
5463 if (ComputeStoreField(ToType(map), name, &lookup)) { | |
5464 HCheckMaps* checked_object = AddCheckMap(object, map); | |
5465 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | |
5466 } | |
5467 | |
5468 // No luck, do a generic store. | |
5469 return BuildStoreNamedGeneric(object, name, value); | |
5470 } | |
5471 | |
5472 | |
5473 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( | |
5474 PropertyAccessInfo* info) { | 5336 PropertyAccessInfo* info) { |
5475 if (!CanInlinePropertyAccess(type_)) return false; | 5337 if (!CanInlinePropertyAccess(type_)) return false; |
5476 | 5338 |
5477 // Currently only handle Type::Number as a polymorphic case. | 5339 // Currently only handle Type::Number as a polymorphic case. |
5478 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber | 5340 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
5479 // instruction. | 5341 // instruction. |
5480 if (type_->Is(Type::Number())) return false; | 5342 if (type_->Is(Type::Number())) return false; |
5481 | 5343 |
5482 // Values are only compatible for monomorphic load if they all behave the same | 5344 // Values are only compatible for monomorphic load if they all behave the same |
5483 // regarding value wrappers. | 5345 // regarding value wrappers. |
(...skipping 19 matching lines...) Expand all Loading... |
5503 } | 5365 } |
5504 | 5366 |
5505 if (lookup_.IsConstant()) { | 5367 if (lookup_.IsConstant()) { |
5506 return constant_.is_identical_to(info->constant_); | 5368 return constant_.is_identical_to(info->constant_); |
5507 } | 5369 } |
5508 | 5370 |
5509 ASSERT(lookup_.IsField()); | 5371 ASSERT(lookup_.IsField()); |
5510 if (!info->lookup_.IsField()) return false; | 5372 if (!info->lookup_.IsField()) return false; |
5511 | 5373 |
5512 Representation r = access_.representation(); | 5374 Representation r = access_.representation(); |
5513 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; | 5375 if (IsLoad()) { |
| 5376 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; |
| 5377 } else { |
| 5378 if (!info->access_.representation().IsCompatibleForStore(r)) return false; |
| 5379 } |
5514 if (info->access_.offset() != access_.offset()) return false; | 5380 if (info->access_.offset() != access_.offset()) return false; |
5515 if (info->access_.IsInobject() != access_.IsInobject()) return false; | 5381 if (info->access_.IsInobject() != access_.IsInobject()) return false; |
5516 info->GeneralizeRepresentation(r); | 5382 info->GeneralizeRepresentation(r); |
5517 return true; | 5383 return true; |
5518 } | 5384 } |
5519 | 5385 |
5520 | 5386 |
5521 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { | 5387 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { |
5522 if (!type_->IsClass()) return true; | 5388 if (!type_->IsClass()) return true; |
5523 map()->LookupDescriptor(NULL, *name_, &lookup_); | 5389 map()->LookupDescriptor(NULL, *name_, &lookup_); |
5524 return LoadResult(map()); | 5390 return LoadResult(map()); |
5525 } | 5391 } |
5526 | 5392 |
5527 | 5393 |
5528 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { | 5394 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { |
| 5395 if (!IsLoad() && lookup_.IsProperty() && |
| 5396 (lookup_.IsReadOnly() || !lookup_.IsCacheable())) { |
| 5397 return false; |
| 5398 } |
| 5399 |
5529 if (lookup_.IsField()) { | 5400 if (lookup_.IsField()) { |
5530 access_ = HObjectAccess::ForField(map, &lookup_, name_); | 5401 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
5531 } else if (lookup_.IsPropertyCallbacks()) { | 5402 } else if (lookup_.IsPropertyCallbacks()) { |
5532 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); | 5403 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
5533 if (!callback->IsAccessorPair()) return false; | 5404 if (!callback->IsAccessorPair()) return false; |
5534 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); | 5405 Object* raw_accessor = IsLoad() |
5535 if (!getter->IsJSFunction()) return false; | 5406 ? Handle<AccessorPair>::cast(callback)->getter() |
5536 Handle<JSFunction> accessor = handle(JSFunction::cast(getter)); | 5407 : Handle<AccessorPair>::cast(callback)->setter(); |
| 5408 if (!raw_accessor->IsJSFunction()) return false; |
| 5409 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor)); |
5537 CallOptimization call_optimization(accessor); | 5410 CallOptimization call_optimization(accessor); |
5538 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | 5411 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. |
5539 if (call_optimization.is_simple_api_call()) return false; | 5412 if (call_optimization.is_simple_api_call()) return false; |
5540 accessor_ = accessor; | 5413 accessor_ = accessor; |
5541 } else if (lookup_.IsConstant()) { | 5414 } else if (lookup_.IsConstant()) { |
5542 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); | 5415 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
5543 } | 5416 } |
5544 | 5417 |
5545 return true; | 5418 return true; |
5546 } | 5419 } |
(...skipping 13 matching lines...) Expand all Loading... |
5560 return false; | 5433 return false; |
5561 } | 5434 } |
5562 map->LookupDescriptor(*holder_, *name_, &lookup_); | 5435 map->LookupDescriptor(*holder_, *name_, &lookup_); |
5563 if (lookup_.IsFound()) return LoadResult(map); | 5436 if (lookup_.IsFound()) return LoadResult(map); |
5564 } | 5437 } |
5565 lookup_.NotFound(); | 5438 lookup_.NotFound(); |
5566 return true; | 5439 return true; |
5567 } | 5440 } |
5568 | 5441 |
5569 | 5442 |
5570 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { | 5443 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { |
5571 if (!CanInlinePropertyAccess(type_)) return false; | 5444 if (!CanInlinePropertyAccess(type_)) return false; |
5572 if (IsJSObjectFieldAccessor()) return true; | 5445 if (IsJSObjectFieldAccessor()) { |
| 5446 // We should never have gathered typefeedback for JSObjectFieldAccessor |
| 5447 // stores. |
| 5448 ASSERT(IsLoad()); |
| 5449 return true; |
| 5450 } |
5573 if (!LookupDescriptor()) return false; | 5451 if (!LookupDescriptor()) return false; |
5574 if (lookup_.IsFound()) return true; | 5452 if (lookup_.IsFound()) { |
5575 return LookupInPrototypes(); | 5453 if (IsLoad()) return true; |
| 5454 return !lookup_.IsReadOnly() && lookup_.IsCacheable(); |
| 5455 } |
| 5456 if (!LookupInPrototypes()) return false; |
| 5457 if (IsLoad()) return true; |
| 5458 |
| 5459 if (lookup_.IsPropertyCallbacks()) return true; |
| 5460 Handle<Map> map = this->map(); |
| 5461 map->LookupTransition(NULL, *name_, &lookup_); |
| 5462 if (lookup_.IsTransitionToField(*map) && map->unused_property_fields() > 0) { |
| 5463 transition_ = handle(lookup_.GetTransitionMapFromMap(*map)); |
| 5464 return true; |
| 5465 } |
| 5466 return false; |
5576 } | 5467 } |
5577 | 5468 |
5578 | 5469 |
5579 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( | 5470 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( |
5580 SmallMapList* types) { | 5471 SmallMapList* types) { |
5581 ASSERT(type_->Is(ToType(types->first()))); | 5472 ASSERT(type_->Is(ToType(types->first()))); |
5582 if (!CanLoadMonomorphic()) return false; | 5473 if (!CanAccessMonomorphic()) return false; |
| 5474 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); |
5583 if (types->length() > kMaxLoadPolymorphism) return false; | 5475 if (types->length() > kMaxLoadPolymorphism) return false; |
5584 | 5476 |
5585 if (IsArrayLength()) { | 5477 if (IsArrayLength()) { |
5586 bool is_fast = IsFastElementsKind(map()->elements_kind()); | 5478 bool is_fast = IsFastElementsKind(map()->elements_kind()); |
5587 for (int i = 1; i < types->length(); ++i) { | 5479 for (int i = 1; i < types->length(); ++i) { |
5588 Handle<Map> test_map = types->at(i); | 5480 Handle<Map> test_map = types->at(i); |
5589 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; | 5481 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; |
5590 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { | 5482 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { |
5591 return false; | 5483 return false; |
5592 } | 5484 } |
5593 } | 5485 } |
5594 return true; | 5486 return true; |
5595 } | 5487 } |
5596 | 5488 |
5597 HObjectAccess access = HObjectAccess::ForMap(); // bogus default | 5489 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
5598 if (GetJSObjectFieldAccess(&access)) { | 5490 if (GetJSObjectFieldAccess(&access)) { |
5599 for (int i = 1; i < types->length(); ++i) { | 5491 for (int i = 1; i < types->length(); ++i) { |
5600 PropertyAccessInfo test_info(builder_, ToType(types->at(i)), name_); | 5492 PropertyAccessInfo test_info( |
| 5493 builder_, access_type_, ToType(types->at(i)), name_); |
5601 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default | 5494 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default |
5602 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; | 5495 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; |
5603 if (!access.Equals(test_access)) return false; | 5496 if (!access.Equals(test_access)) return false; |
5604 } | 5497 } |
5605 return true; | 5498 return true; |
5606 } | 5499 } |
5607 | 5500 |
5608 // Currently only handle Type::Number as a polymorphic case. | 5501 // Currently only handle Type::Number as a polymorphic case. |
5609 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber | 5502 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
5610 // instruction. | 5503 // instruction. |
5611 if (type_->Is(Type::Number())) return false; | 5504 if (type_->Is(Type::Number())) return false; |
5612 | 5505 |
| 5506 // Multiple maps cannot transition to the same target map. |
| 5507 ASSERT(!IsLoad() || !lookup_.IsTransition()); |
| 5508 if (lookup_.IsTransition() && types->length() > 1) return false; |
| 5509 |
5613 for (int i = 1; i < types->length(); ++i) { | 5510 for (int i = 1; i < types->length(); ++i) { |
5614 PropertyAccessInfo test_info(builder_, ToType(types->at(i)), name_); | 5511 PropertyAccessInfo test_info( |
5615 if (!test_info.IsCompatibleForLoad(this)) return false; | 5512 builder_, access_type_, ToType(types->at(i)), name_); |
| 5513 if (!test_info.IsCompatible(this)) return false; |
5616 } | 5514 } |
5617 | 5515 |
5618 return true; | 5516 return true; |
5619 } | 5517 } |
5620 | 5518 |
5621 | 5519 |
5622 static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) { | 5520 static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) { |
5623 return type->Is(Type::NumberOrString()) && | 5521 return type->Is(Type::NumberOrString()) && |
5624 target->shared()->is_classic_mode() && | 5522 target->shared()->is_classic_mode() && |
5625 !target->shared()->native(); | 5523 !target->shared()->native(); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5667 Add<HPushArgument>(Pop()); | 5565 Add<HPushArgument>(Pop()); |
5668 return BuildCallConstantFunction(info->accessor(), 1); | 5566 return BuildCallConstantFunction(info->accessor(), 1); |
5669 } | 5567 } |
5670 } | 5568 } |
5671 | 5569 |
5672 ASSERT(info->lookup()->IsConstant()); | 5570 ASSERT(info->lookup()->IsConstant()); |
5673 return New<HConstant>(info->constant()); | 5571 return New<HConstant>(info->constant()); |
5674 } | 5572 } |
5675 | 5573 |
5676 | 5574 |
| 5575 HInstruction* HOptimizedGraphBuilder::BuildStoreMonomorphic( |
| 5576 PropertyAccessInfo* info, |
| 5577 HValue* checked_object, |
| 5578 HValue* value, |
| 5579 BailoutId ast_id, |
| 5580 BailoutId return_id, |
| 5581 bool can_inline_accessor) { |
| 5582 ASSERT(!info->IsJSObjectFieldAccessor()); |
| 5583 |
| 5584 if (info->has_holder()) { |
| 5585 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); |
| 5586 BuildCheckPrototypeMaps(prototype, info->holder()); |
| 5587 } |
| 5588 |
| 5589 if (info->lookup()->IsPropertyCallbacks()) { |
| 5590 if (NeedsWrappingFor(info->type(), info->accessor())) { |
| 5591 HValue* function = Add<HConstant>(info->accessor()); |
| 5592 Add<HPushArgument>(checked_object); |
| 5593 Add<HPushArgument>(value); |
| 5594 return New<HCallFunction>(function, 2, WRAP_AND_CALL); |
| 5595 } else { |
| 5596 Push(checked_object); |
| 5597 Push(value); |
| 5598 if (FLAG_inline_accessors && |
| 5599 can_inline_accessor && |
| 5600 TryInlineSetter(info->accessor(), ast_id, return_id, value)) { |
| 5601 return NULL; |
| 5602 } |
| 5603 PushArgumentsFromEnvironment(2); |
| 5604 return BuildCallConstantFunction(info->accessor(), 2); |
| 5605 } |
| 5606 } |
| 5607 |
| 5608 if (info->lookup()->IsConstant()) { |
| 5609 // Check whether we are trying to store the same constant. |
| 5610 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); |
| 5611 } |
| 5612 |
| 5613 ASSERT(info->lookup()->IsField() || info->lookup()->IsTransition()); |
| 5614 return BuildStoreNamedField(info, checked_object, value); |
| 5615 } |
| 5616 |
| 5617 |
5677 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 5618 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
5678 BailoutId ast_id, | 5619 BailoutId ast_id, |
5679 BailoutId return_id, | 5620 BailoutId return_id, |
5680 HValue* object, | 5621 HValue* object, |
5681 SmallMapList* types, | 5622 SmallMapList* types, |
5682 Handle<String> name) { | 5623 Handle<String> name) { |
5683 // Something did not match; must use a polymorphic load. | 5624 // Something did not match; must use a polymorphic load. |
5684 int count = 0; | 5625 int count = 0; |
5685 HBasicBlock* join = NULL; | 5626 HBasicBlock* join = NULL; |
5686 HBasicBlock* number_block = NULL; | 5627 HBasicBlock* number_block = NULL; |
5687 bool handled_string = false; | 5628 bool handled_string = false; |
5688 | 5629 |
5689 bool handle_smi = false; | 5630 bool handle_smi = false; |
5690 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5631 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
5691 PropertyAccessInfo info(this, ToType(types->at(i)), name); | 5632 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
5692 if (info.type()->Is(Type::String())) { | 5633 if (info.type()->Is(Type::String())) { |
5693 if (handled_string) continue; | 5634 if (handled_string) continue; |
5694 handled_string = true; | 5635 handled_string = true; |
5695 } | 5636 } |
5696 if (info.CanLoadMonomorphic()) { | 5637 if (info.CanAccessMonomorphic()) { |
5697 count++; | 5638 count++; |
5698 if (info.type()->Is(Type::Number())) { | 5639 if (info.type()->Is(Type::Number())) { |
5699 handle_smi = true; | 5640 handle_smi = true; |
5700 break; | 5641 break; |
5701 } | 5642 } |
5702 } | 5643 } |
5703 } | 5644 } |
5704 | 5645 |
5705 count = 0; | 5646 count = 0; |
5706 HControlInstruction* smi_check = NULL; | 5647 HControlInstruction* smi_check = NULL; |
5707 handled_string = false; | 5648 handled_string = false; |
5708 | 5649 |
5709 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5650 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
5710 PropertyAccessInfo info(this, ToType(types->at(i)), name); | 5651 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
5711 if (info.type()->Is(Type::String())) { | 5652 if (info.type()->Is(Type::String())) { |
5712 if (handled_string) continue; | 5653 if (handled_string) continue; |
5713 handled_string = true; | 5654 handled_string = true; |
5714 } | 5655 } |
5715 if (!info.CanLoadMonomorphic()) continue; | 5656 if (!info.CanAccessMonomorphic()) continue; |
5716 | 5657 |
5717 if (count == 0) { | 5658 if (count == 0) { |
5718 join = graph()->CreateBasicBlock(); | 5659 join = graph()->CreateBasicBlock(); |
5719 if (handle_smi) { | 5660 if (handle_smi) { |
5720 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 5661 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
5721 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 5662 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
5722 number_block = graph()->CreateBasicBlock(); | 5663 number_block = graph()->CreateBasicBlock(); |
5723 smi_check = New<HIsSmiAndBranch>( | 5664 smi_check = New<HIsSmiAndBranch>( |
5724 object, empty_smi_block, not_smi_block); | 5665 object, empty_smi_block, not_smi_block); |
5725 FinishCurrentBlock(smi_check); | 5666 FinishCurrentBlock(smi_check); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5794 } | 5735 } |
5795 } | 5736 } |
5796 | 5737 |
5797 ASSERT(join != NULL); | 5738 ASSERT(join != NULL); |
5798 join->SetJoinId(ast_id); | 5739 join->SetJoinId(ast_id); |
5799 set_current_block(join); | 5740 set_current_block(join); |
5800 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 5741 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
5801 } | 5742 } |
5802 | 5743 |
5803 | 5744 |
5804 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( | |
5805 BailoutId assignment_id, | |
5806 HValue* object, | |
5807 HValue* value, | |
5808 SmallMapList* types, | |
5809 Handle<String> name) { | |
5810 // Use monomorphic store if property lookup results in the same field index | |
5811 // for all maps. Requires special map check on the set of all handled maps. | |
5812 if (types->length() > kMaxStorePolymorphism) return false; | |
5813 | |
5814 LookupResult lookup(isolate()); | |
5815 int count; | |
5816 Representation representation = Representation::None(); | |
5817 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | |
5818 for (count = 0; count < types->length(); ++count) { | |
5819 Handle<Map> map = types->at(count); | |
5820 // Pass false to ignore transitions. | |
5821 if (!ComputeStoreField(ToType(map), name, &lookup, false)) break; | |
5822 ASSERT(!map->is_observed()); | |
5823 | |
5824 HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); | |
5825 Representation new_representation = new_access.representation(); | |
5826 | |
5827 if (count == 0) { | |
5828 // First time through the loop; set access and representation. | |
5829 access = new_access; | |
5830 representation = new_representation; | |
5831 } else if (!representation.IsCompatibleForStore(new_representation)) { | |
5832 // Representations did not match. | |
5833 break; | |
5834 } else if (access.offset() != new_access.offset()) { | |
5835 // Offsets did not match. | |
5836 break; | |
5837 } else if (access.IsInobject() != new_access.IsInobject()) { | |
5838 // In-objectness did not match. | |
5839 break; | |
5840 } | |
5841 } | |
5842 | |
5843 if (count != types->length()) return false; | |
5844 | |
5845 // Everything matched; can use monomorphic store. | |
5846 BuildCheckHeapObject(object); | |
5847 HCheckMaps* checked_object = Add<HCheckMaps>(object, types); | |
5848 HInstruction* store; | |
5849 CHECK_ALIVE_OR_RETURN( | |
5850 store = BuildStoreNamedField( | |
5851 checked_object, name, value, types->at(count - 1), &lookup), | |
5852 true); | |
5853 if (!ast_context()->IsEffect()) Push(value); | |
5854 AddInstruction(store); | |
5855 Add<HSimulate>(assignment_id); | |
5856 if (!ast_context()->IsEffect()) Drop(1); | |
5857 ast_context()->ReturnValue(value); | |
5858 return true; | |
5859 } | |
5860 | |
5861 | |
5862 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( | 5745 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( |
5863 BailoutId assignment_id, | 5746 BailoutId assignment_id, |
| 5747 BailoutId return_id, |
5864 HValue* object, | 5748 HValue* object, |
5865 HValue* value, | 5749 HValue* value, |
5866 SmallMapList* types, | 5750 SmallMapList* types, |
5867 Handle<String> name) { | 5751 Handle<String> name) { |
5868 if (TryStorePolymorphicAsMonomorphic( | |
5869 assignment_id, object, value, types, name)) { | |
5870 return; | |
5871 } | |
5872 | |
5873 // TODO(ager): We should recognize when the prototype chains for different | |
5874 // maps are identical. In that case we can avoid repeatedly generating the | |
5875 // same prototype map checks. | |
5876 int count = 0; | 5752 int count = 0; |
5877 HBasicBlock* join = NULL; | 5753 HBasicBlock* join = NULL; |
| 5754 // TODO(verwaest): Unify with polymorphic load handling. |
5878 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 5755 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
5879 Handle<Map> map = types->at(i); | 5756 PropertyAccessInfo info(this, STORE, ToType(types->at(i)), name); |
5880 LookupResult lookup(isolate()); | 5757 if (info.CanAccessMonomorphic()) { |
5881 if (ComputeStoreField(ToType(map), name, &lookup)) { | |
5882 if (count == 0) { | 5758 if (count == 0) { |
5883 BuildCheckHeapObject(object); | 5759 BuildCheckHeapObject(object); |
5884 join = graph()->CreateBasicBlock(); | 5760 join = graph()->CreateBasicBlock(); |
5885 } | 5761 } |
5886 ++count; | 5762 ++count; |
5887 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5763 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
5888 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5764 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
5889 HCompareMap* compare = New<HCompareMap>(object, map, if_true, if_false); | 5765 HCompareMap* compare = New<HCompareMap>( |
| 5766 object, info.map(), if_true, if_false); |
5890 FinishCurrentBlock(compare); | 5767 FinishCurrentBlock(compare); |
5891 | 5768 |
5892 set_current_block(if_true); | 5769 set_current_block(if_true); |
5893 HInstruction* instr; | |
5894 CHECK_ALIVE(instr = BuildStoreNamedField( | |
5895 compare, name, value, map, &lookup)); | |
5896 // Goto will add the HSimulate for the store. | |
5897 AddInstruction(instr); | |
5898 if (!ast_context()->IsEffect()) Push(value); | |
5899 Goto(join); | |
5900 | 5770 |
| 5771 HInstruction* store; |
| 5772 store = BuildStoreMonomorphic( |
| 5773 &info, compare, value, assignment_id, return_id, |
| 5774 FLAG_polymorphic_inlining); |
| 5775 |
| 5776 if (store == NULL) { |
| 5777 if (HasStackOverflow()) return; |
| 5778 } else { |
| 5779 ASSERT(!store->IsLinked()); |
| 5780 AddInstruction(store); |
| 5781 if (!ast_context()->IsEffect()) Push(value); |
| 5782 } |
| 5783 |
| 5784 if (current_block() != NULL) Goto(join); |
5901 set_current_block(if_false); | 5785 set_current_block(if_false); |
5902 } | 5786 } |
5903 } | 5787 } |
5904 | 5788 |
5905 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5789 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
5906 // know about and do not want to handle ones we've never seen. Otherwise | 5790 // know about and do not want to handle ones we've never seen. Otherwise |
5907 // use a generic IC. | 5791 // use a generic IC. |
5908 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5792 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
5909 FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); | 5793 FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); |
5910 } else { | 5794 } else { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5952 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { | 5836 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { |
5953 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); | 5837 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); |
5954 types->FilterForPossibleTransitions(root_map); | 5838 types->FilterForPossibleTransitions(root_map); |
5955 monomorphic = types->length() == 1; | 5839 monomorphic = types->length() == 1; |
5956 } | 5840 } |
5957 return monomorphic && CanInlinePropertyAccess( | 5841 return monomorphic && CanInlinePropertyAccess( |
5958 IC::MapToType<Type>(types->first(), zone)); | 5842 IC::MapToType<Type>(types->first(), zone)); |
5959 } | 5843 } |
5960 | 5844 |
5961 | 5845 |
| 5846 static bool AreStringTypes(SmallMapList* types) { |
| 5847 for (int i = 0; i < types->length(); i++) { |
| 5848 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; |
| 5849 } |
| 5850 return true; |
| 5851 } |
| 5852 |
| 5853 |
5962 void HOptimizedGraphBuilder::BuildStore(Expression* expr, | 5854 void HOptimizedGraphBuilder::BuildStore(Expression* expr, |
5963 Property* prop, | 5855 Property* prop, |
5964 BailoutId ast_id, | 5856 BailoutId ast_id, |
5965 BailoutId return_id, | 5857 BailoutId return_id, |
5966 bool is_uninitialized) { | 5858 bool is_uninitialized) { |
5967 HValue* value = environment()->ExpressionStackAt(0); | |
5968 | |
5969 if (!prop->key()->IsPropertyName()) { | 5859 if (!prop->key()->IsPropertyName()) { |
5970 // Keyed store. | 5860 // Keyed store. |
| 5861 HValue* value = environment()->ExpressionStackAt(0); |
5971 HValue* key = environment()->ExpressionStackAt(1); | 5862 HValue* key = environment()->ExpressionStackAt(1); |
5972 HValue* object = environment()->ExpressionStackAt(2); | 5863 HValue* object = environment()->ExpressionStackAt(2); |
5973 bool has_side_effects = false; | 5864 bool has_side_effects = false; |
5974 HandleKeyedElementAccess(object, key, value, expr, | 5865 HandleKeyedElementAccess(object, key, value, expr, |
5975 true, // is_store | 5866 true, // is_store |
5976 &has_side_effects); | 5867 &has_side_effects); |
5977 Drop(3); | 5868 Drop(3); |
5978 Push(value); | 5869 Push(value); |
5979 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); | 5870 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); |
5980 return ast_context()->ReturnValue(Pop()); | 5871 return ast_context()->ReturnValue(Pop()); |
5981 } | 5872 } |
5982 | 5873 |
5983 // Named store. | 5874 // Named store. |
5984 HValue* object = environment()->ExpressionStackAt(1); | 5875 HValue* value = Pop(); |
5985 | 5876 HValue* object = Pop(); |
5986 if (is_uninitialized) { | |
5987 Add<HDeoptimize>("Insufficient type feedback for property assignment", | |
5988 Deoptimizer::SOFT); | |
5989 } | |
5990 | 5877 |
5991 Literal* key = prop->key()->AsLiteral(); | 5878 Literal* key = prop->key()->AsLiteral(); |
5992 Handle<String> name = Handle<String>::cast(key->value()); | 5879 Handle<String> name = Handle<String>::cast(key->value()); |
5993 ASSERT(!name.is_null()); | 5880 ASSERT(!name.is_null()); |
5994 | 5881 |
5995 HInstruction* instr = NULL; | 5882 HInstruction* instr = NULL; |
5996 | 5883 |
5997 SmallMapList* types; | 5884 SmallMapList* types; |
5998 bool monomorphic = ComputeReceiverTypes(expr, object, &types, zone()); | 5885 ComputeReceiverTypes(expr, object, &types, zone()); |
5999 | 5886 |
6000 if (monomorphic) { | 5887 if (types->length() > 0) { |
6001 Handle<Map> map = types->first(); | 5888 PropertyAccessInfo info(this, STORE, ToType(types->first()), name); |
6002 Handle<JSFunction> setter; | 5889 if (!info.CanAccessAsMonomorphic(types)) { |
6003 Handle<JSObject> holder; | 5890 return HandlePolymorphicStoreNamedField( |
6004 if (LookupSetter(map, name, &setter, &holder, zone())) { | 5891 ast_id, return_id, object, value, types, name); |
6005 AddCheckMap(object, map); | 5892 } |
6006 AddCheckPrototypeMaps(holder, map); | 5893 |
6007 bool needs_wrapping = NeedsWrappingFor(ToType(map), setter); | 5894 ASSERT(!info.type()->Is(Type::Number())); |
6008 bool try_inline = FLAG_inline_accessors && !needs_wrapping; | 5895 BuildCheckHeapObject(object); |
6009 if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) { | 5896 HValue* checked_object; |
6010 return; | 5897 if (AreStringTypes(types)) { |
6011 } | 5898 checked_object = Add<HCheckInstanceType>( |
6012 Drop(2); | 5899 object, HCheckInstanceType::IS_STRING); |
6013 Add<HPushArgument>(object); | |
6014 Add<HPushArgument>(value); | |
6015 if (needs_wrapping) { | |
6016 HValue* function = Add<HConstant>(setter); | |
6017 instr = New<HCallFunction>(function, 2, WRAP_AND_CALL); | |
6018 } else { | |
6019 instr = BuildCallConstantFunction(setter, 2); | |
6020 } | |
6021 } else { | 5900 } else { |
6022 Drop(2); | 5901 checked_object = Add<HCheckMaps>(object, types); |
6023 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | |
6024 name, | |
6025 value, | |
6026 map)); | |
6027 } | 5902 } |
6028 } else if (types != NULL && types->length() > 1) { | 5903 instr = BuildStoreMonomorphic( |
6029 Drop(2); | 5904 &info, checked_object, value, ast_id, return_id); |
6030 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); | 5905 if (instr == NULL) return; |
| 5906 ASSERT(!instr->IsLinked()); |
6031 } else { | 5907 } else { |
6032 Drop(2); | 5908 instr = BuildStoreNamedGeneric(object, name, value, is_uninitialized); |
6033 instr = BuildStoreNamedGeneric(object, name, value); | |
6034 } | 5909 } |
6035 | 5910 |
6036 if (!ast_context()->IsEffect()) Push(value); | 5911 if (!ast_context()->IsEffect()) Push(value); |
6037 AddInstruction(instr); | 5912 AddInstruction(instr); |
6038 if (instr->HasObservableSideEffects()) { | 5913 if (instr->HasObservableSideEffects()) { |
6039 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5914 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
6040 } | 5915 } |
6041 if (!ast_context()->IsEffect()) Drop(1); | 5916 if (!ast_context()->IsEffect()) Drop(1); |
6042 return ast_context()->ReturnValue(value); | 5917 return ast_context()->ReturnValue(value); |
6043 } | 5918 } |
(...skipping 787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6831 void HOptimizedGraphBuilder::PushLoad(Property* expr, | 6706 void HOptimizedGraphBuilder::PushLoad(Property* expr, |
6832 HValue* object, | 6707 HValue* object, |
6833 HValue* key) { | 6708 HValue* key) { |
6834 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); | 6709 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
6835 Push(object); | 6710 Push(object); |
6836 if (key != NULL) Push(key); | 6711 if (key != NULL) Push(key); |
6837 BuildLoad(expr, expr->LoadId()); | 6712 BuildLoad(expr, expr->LoadId()); |
6838 } | 6713 } |
6839 | 6714 |
6840 | 6715 |
6841 static bool AreStringTypes(SmallMapList* types) { | |
6842 for (int i = 0; i < types->length(); i++) { | |
6843 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | |
6844 } | |
6845 return true; | |
6846 } | |
6847 | |
6848 | |
6849 void HOptimizedGraphBuilder::BuildLoad(Property* expr, | 6716 void HOptimizedGraphBuilder::BuildLoad(Property* expr, |
6850 BailoutId ast_id) { | 6717 BailoutId ast_id) { |
6851 HInstruction* instr = NULL; | 6718 HInstruction* instr = NULL; |
6852 if (expr->IsStringAccess()) { | 6719 if (expr->IsStringAccess()) { |
6853 HValue* index = Pop(); | 6720 HValue* index = Pop(); |
6854 HValue* string = Pop(); | 6721 HValue* string = Pop(); |
6855 HInstruction* char_code = BuildStringCharCodeAt(string, index); | 6722 HInstruction* char_code = BuildStringCharCodeAt(string, index); |
6856 AddInstruction(char_code); | 6723 AddInstruction(char_code); |
6857 instr = NewUncasted<HStringCharFromCode>(char_code); | 6724 instr = NewUncasted<HStringCharFromCode>(char_code); |
6858 | 6725 |
6859 } else if (expr->IsFunctionPrototype()) { | 6726 } else if (expr->IsFunctionPrototype()) { |
6860 HValue* function = Pop(); | 6727 HValue* function = Pop(); |
6861 BuildCheckHeapObject(function); | 6728 BuildCheckHeapObject(function); |
6862 instr = New<HLoadFunctionPrototype>(function); | 6729 instr = New<HLoadFunctionPrototype>(function); |
6863 | 6730 |
6864 } else if (expr->key()->IsPropertyName()) { | 6731 } else if (expr->key()->IsPropertyName()) { |
6865 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 6732 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
6866 HValue* object = Pop(); | 6733 HValue* object = Pop(); |
6867 | 6734 |
6868 SmallMapList* types; | 6735 SmallMapList* types; |
6869 ComputeReceiverTypes(expr, object, &types, zone()); | 6736 ComputeReceiverTypes(expr, object, &types, zone()); |
6870 ASSERT(types != NULL); | 6737 ASSERT(types != NULL); |
6871 | 6738 |
6872 if (types->length() > 0) { | 6739 if (types->length() > 0) { |
6873 PropertyAccessInfo info(this, ToType(types->first()), name); | 6740 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name); |
6874 if (!info.CanLoadAsMonomorphic(types)) { | 6741 if (!info.CanAccessAsMonomorphic(types)) { |
6875 return HandlePolymorphicLoadNamedField( | 6742 return HandlePolymorphicLoadNamedField( |
6876 ast_id, expr->LoadId(), object, types, name); | 6743 ast_id, expr->LoadId(), object, types, name); |
6877 } | 6744 } |
6878 | 6745 |
6879 HValue* checked_object; | 6746 HValue* checked_object; |
6880 // Type::Number() is only supported by polymorphic load/call handling. | 6747 // Type::Number() is only supported by polymorphic load/call handling. |
6881 ASSERT(!info.type()->Is(Type::Number())); | 6748 ASSERT(!info.type()->Is(Type::Number())); |
6882 BuildCheckHeapObject(object); | 6749 BuildCheckHeapObject(object); |
6883 if (AreStringTypes(types)) { | 6750 if (AreStringTypes(types)) { |
6884 checked_object = | 6751 checked_object = |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7071 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6938 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
7072 FunctionSorter order[kMaxCallPolymorphism]; | 6939 FunctionSorter order[kMaxCallPolymorphism]; |
7073 | 6940 |
7074 bool handle_smi = false; | 6941 bool handle_smi = false; |
7075 bool handled_string = false; | 6942 bool handled_string = false; |
7076 int ordered_functions = 0; | 6943 int ordered_functions = 0; |
7077 | 6944 |
7078 for (int i = 0; | 6945 for (int i = 0; |
7079 i < types->length() && ordered_functions < kMaxCallPolymorphism; | 6946 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
7080 ++i) { | 6947 ++i) { |
7081 PropertyAccessInfo info(this, ToType(types->at(i)), name); | 6948 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
7082 if (info.CanLoadMonomorphic() && | 6949 if (info.CanAccessMonomorphic() && |
7083 info.lookup()->IsConstant() && | 6950 info.lookup()->IsConstant() && |
7084 info.constant()->IsJSFunction()) { | 6951 info.constant()->IsJSFunction()) { |
7085 if (info.type()->Is(Type::String())) { | 6952 if (info.type()->Is(Type::String())) { |
7086 if (handled_string) continue; | 6953 if (handled_string) continue; |
7087 handled_string = true; | 6954 handled_string = true; |
7088 } | 6955 } |
7089 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); | 6956 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
7090 if (info.type()->Is(Type::Number())) { | 6957 if (info.type()->Is(Type::Number())) { |
7091 handle_smi = true; | 6958 handle_smi = true; |
7092 } | 6959 } |
7093 expr->set_target(target); | 6960 expr->set_target(target); |
7094 order[ordered_functions++] = | 6961 order[ordered_functions++] = |
7095 FunctionSorter(i, | 6962 FunctionSorter(i, |
7096 expr->target()->shared()->profiler_ticks(), | 6963 expr->target()->shared()->profiler_ticks(), |
7097 InliningAstSize(expr->target()), | 6964 InliningAstSize(expr->target()), |
7098 expr->target()->shared()->SourceSize()); | 6965 expr->target()->shared()->SourceSize()); |
7099 } | 6966 } |
7100 } | 6967 } |
7101 | 6968 |
7102 std::sort(order, order + ordered_functions); | 6969 std::sort(order, order + ordered_functions); |
7103 | 6970 |
7104 HBasicBlock* number_block = NULL; | 6971 HBasicBlock* number_block = NULL; |
7105 HBasicBlock* join = NULL; | 6972 HBasicBlock* join = NULL; |
7106 handled_string = false; | 6973 handled_string = false; |
7107 int count = 0; | 6974 int count = 0; |
7108 | 6975 |
7109 for (int fn = 0; fn < ordered_functions; ++fn) { | 6976 for (int fn = 0; fn < ordered_functions; ++fn) { |
7110 int i = order[fn].index(); | 6977 int i = order[fn].index(); |
7111 PropertyAccessInfo info(this, ToType(types->at(i)), name); | 6978 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
7112 if (info.type()->Is(Type::String())) { | 6979 if (info.type()->Is(Type::String())) { |
7113 if (handled_string) continue; | 6980 if (handled_string) continue; |
7114 handled_string = true; | 6981 handled_string = true; |
7115 } | 6982 } |
7116 // Reloads the target. | 6983 // Reloads the target. |
7117 info.CanLoadMonomorphic(); | 6984 info.CanAccessMonomorphic(); |
7118 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); | 6985 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
7119 | 6986 |
7120 expr->set_target(target); | 6987 expr->set_target(target); |
7121 if (count == 0) { | 6988 if (count == 0) { |
7122 // Only needed once. | 6989 // Only needed once. |
7123 join = graph()->CreateBasicBlock(); | 6990 join = graph()->CreateBasicBlock(); |
7124 if (handle_smi) { | 6991 if (handle_smi) { |
7125 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6992 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
7126 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6993 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
7127 number_block = graph()->CreateBasicBlock(); | 6994 number_block = graph()->CreateBasicBlock(); |
(...skipping 966 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8094 Property* prop = callee->AsProperty(); | 7961 Property* prop = callee->AsProperty(); |
8095 if (prop != NULL) { | 7962 if (prop != NULL) { |
8096 CHECK_ALIVE(VisitForValue(prop->obj())); | 7963 CHECK_ALIVE(VisitForValue(prop->obj())); |
8097 HValue* receiver = Top(); | 7964 HValue* receiver = Top(); |
8098 | 7965 |
8099 SmallMapList* types; | 7966 SmallMapList* types; |
8100 ComputeReceiverTypes(expr, receiver, &types, zone()); | 7967 ComputeReceiverTypes(expr, receiver, &types, zone()); |
8101 | 7968 |
8102 if (prop->key()->IsPropertyName() && types->length() > 0) { | 7969 if (prop->key()->IsPropertyName() && types->length() > 0) { |
8103 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | 7970 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
8104 PropertyAccessInfo info(this, ToType(types->first()), name); | 7971 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name); |
8105 if (!info.CanLoadAsMonomorphic(types)) { | 7972 if (!info.CanAccessAsMonomorphic(types)) { |
8106 HandlePolymorphicCallNamed(expr, receiver, types, name); | 7973 HandlePolymorphicCallNamed(expr, receiver, types, name); |
8107 return; | 7974 return; |
8108 } | 7975 } |
8109 } | 7976 } |
8110 | 7977 |
8111 HValue* key = NULL; | 7978 HValue* key = NULL; |
8112 if (!prop->key()->IsPropertyName()) { | 7979 if (!prop->key()->IsPropertyName()) { |
8113 CHECK_ALIVE(VisitForValue(prop->key())); | 7980 CHECK_ALIVE(VisitForValue(prop->key())); |
8114 key = Pop(); | 7981 key = Pop(); |
8115 } | 7982 } |
(...skipping 3244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11360 if (ShouldProduceTraceOutput()) { | 11227 if (ShouldProduceTraceOutput()) { |
11361 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11228 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11362 } | 11229 } |
11363 | 11230 |
11364 #ifdef DEBUG | 11231 #ifdef DEBUG |
11365 graph_->Verify(false); // No full verify. | 11232 graph_->Verify(false); // No full verify. |
11366 #endif | 11233 #endif |
11367 } | 11234 } |
11368 | 11235 |
11369 } } // namespace v8::internal | 11236 } } // namespace v8::internal |
OLD | NEW |