| 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 |