| 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 4906 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4917 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); | 4917 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); |
| 4918 Handle<FixedArray> literals(closure->literals()); | 4918 Handle<FixedArray> literals(closure->literals()); |
| 4919 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, | 4919 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, |
| 4920 expr->pattern(), | 4920 expr->pattern(), |
| 4921 expr->flags(), | 4921 expr->flags(), |
| 4922 expr->literal_index()); | 4922 expr->literal_index()); |
| 4923 return ast_context()->ReturnInstruction(instr, expr->id()); | 4923 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4924 } | 4924 } |
| 4925 | 4925 |
| 4926 | 4926 |
| 4927 static bool CanInlinePropertyAccess(Map* type) { | 4927 static bool CanInlinePropertyAccess(Handle<HeapType> type) { |
| 4928 return type->IsJSObjectMap() && | 4928 if (type->Is(HeapType::NumberOrString())) return true; |
| 4929 !type->is_dictionary_map() && | 4929 if (!type->IsClass()) return false; |
| 4930 !type->has_named_interceptor(); | 4930 Handle<Map> map = type->AsClass(); |
| 4931 return map->IsJSObjectMap() && |
| 4932 !map->is_dictionary_map() && |
| 4933 !map->has_named_interceptor(); |
| 4931 } | 4934 } |
| 4932 | 4935 |
| 4933 | 4936 |
| 4934 static void LookupInPrototypes(Handle<Map> map, | 4937 static void LookupInPrototypes(Handle<Map> map, |
| 4935 Handle<String> name, | 4938 Handle<String> name, |
| 4936 LookupResult* lookup) { | 4939 LookupResult* lookup) { |
| 4937 while (map->prototype()->IsJSObject()) { | 4940 while (map->prototype()->IsJSObject()) { |
| 4938 Handle<JSObject> holder(JSObject::cast(map->prototype())); | 4941 Handle<JSObject> holder(JSObject::cast(map->prototype())); |
| 4939 map = Handle<Map>(holder->map()); | 4942 map = handle(holder->map()); |
| 4940 if (!CanInlinePropertyAccess(*map)) break; | 4943 if (!CanInlinePropertyAccess(IC::MapToType(map))) break; |
| 4941 map->LookupDescriptor(*holder, *name, lookup); | 4944 map->LookupDescriptor(*holder, *name, lookup); |
| 4942 if (lookup->IsFound()) return; | 4945 if (lookup->IsFound()) return; |
| 4943 } | 4946 } |
| 4944 lookup->NotFound(); | 4947 lookup->NotFound(); |
| 4945 } | 4948 } |
| 4946 | 4949 |
| 4947 | 4950 |
| 4948 // Tries to find a JavaScript accessor of the given name in the prototype chain | 4951 // Tries to find a JavaScript accessor of the given name in the prototype chain |
| 4949 // starting at the given map. Return true iff there is one, including the | 4952 // starting at the given map. Return true iff there is one, including the |
| 4950 // corresponding AccessorPair plus its holder (which could be null when the | 4953 // corresponding AccessorPair plus its holder (which could be null when the |
| (...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5431 function_strict_mode_flag()); | 5434 function_strict_mode_flag()); |
| 5432 } | 5435 } |
| 5433 | 5436 |
| 5434 | 5437 |
| 5435 // Sets the lookup result and returns true if the load/store can be inlined. | 5438 // Sets the lookup result and returns true if the load/store can be inlined. |
| 5436 static bool ComputeStoreField(Handle<Map> type, | 5439 static bool ComputeStoreField(Handle<Map> type, |
| 5437 Handle<String> name, | 5440 Handle<String> name, |
| 5438 LookupResult* lookup, | 5441 LookupResult* lookup, |
| 5439 bool lookup_transition = true) { | 5442 bool lookup_transition = true) { |
| 5440 ASSERT(!type->is_observed()); | 5443 ASSERT(!type->is_observed()); |
| 5441 if (!CanInlinePropertyAccess(*type)) { | 5444 if (!CanInlinePropertyAccess(IC::MapToType(type))) { |
| 5442 lookup->NotFound(); | 5445 lookup->NotFound(); |
| 5443 return false; | 5446 return false; |
| 5444 } | 5447 } |
| 5445 // If we directly find a field, the access can be inlined. | 5448 // If we directly find a field, the access can be inlined. |
| 5446 type->LookupDescriptor(NULL, *name, lookup); | 5449 type->LookupDescriptor(NULL, *name, lookup); |
| 5447 if (lookup->IsField()) return true; | 5450 if (lookup->IsField()) return true; |
| 5448 | 5451 |
| 5449 if (!lookup_transition) return false; | 5452 if (!lookup_transition) return false; |
| 5450 | 5453 |
| 5451 type->LookupTransition(NULL, *name, lookup); | 5454 type->LookupTransition(NULL, *name, lookup); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 5466 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | 5469 return BuildStoreNamedField(checked_object, name, value, map, &lookup); |
| 5467 } | 5470 } |
| 5468 | 5471 |
| 5469 // No luck, do a generic store. | 5472 // No luck, do a generic store. |
| 5470 return BuildStoreNamedGeneric(object, name, value); | 5473 return BuildStoreNamedGeneric(object, name, value); |
| 5471 } | 5474 } |
| 5472 | 5475 |
| 5473 | 5476 |
| 5474 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( | 5477 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( |
| 5475 PropertyAccessInfo* info) { | 5478 PropertyAccessInfo* info) { |
| 5476 if (!CanInlinePropertyAccess(*map_)) return false; | 5479 if (!CanInlinePropertyAccess(type_)) return false; |
| 5480 |
| 5481 // Currently only handle HeapType::Number as a polymorphic case. |
| 5482 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5483 // instruction. |
| 5484 if (type_->Is(HeapType::Number())) return false; |
| 5485 |
| 5486 // Values are only compatible for monomorphic load if they all behave the same |
| 5487 // regarding value wrappers. |
| 5488 if (type_->Is(HeapType::NumberOrString())) { |
| 5489 if (!info->type_->Is(HeapType::NumberOrString())) return false; |
| 5490 } else { |
| 5491 if (info->type_->Is(HeapType::NumberOrString())) return false; |
| 5492 } |
| 5477 | 5493 |
| 5478 if (!LookupDescriptor()) return false; | 5494 if (!LookupDescriptor()) return false; |
| 5479 | 5495 |
| 5480 if (!lookup_.IsFound()) { | 5496 if (!lookup_.IsFound()) { |
| 5481 return (!info->lookup_.IsFound() || info->has_holder()) && | 5497 return (!info->lookup_.IsFound() || info->has_holder()) && |
| 5482 map_->prototype() == info->map_->prototype(); | 5498 map()->prototype() == info->map()->prototype(); |
| 5483 } | 5499 } |
| 5484 | 5500 |
| 5485 // Mismatch if the other access info found the property in the prototype | 5501 // Mismatch if the other access info found the property in the prototype |
| 5486 // chain. | 5502 // chain. |
| 5487 if (info->has_holder()) return false; | 5503 if (info->has_holder()) return false; |
| 5488 | 5504 |
| 5489 if (lookup_.IsPropertyCallbacks()) { | 5505 if (lookup_.IsPropertyCallbacks()) { |
| 5490 return accessor_.is_identical_to(info->accessor_); | 5506 return accessor_.is_identical_to(info->accessor_); |
| 5491 } | 5507 } |
| 5492 | 5508 |
| 5493 if (lookup_.IsConstant()) { | 5509 if (lookup_.IsConstant()) { |
| 5494 return constant_.is_identical_to(info->constant_); | 5510 return constant_.is_identical_to(info->constant_); |
| 5495 } | 5511 } |
| 5496 | 5512 |
| 5497 ASSERT(lookup_.IsField()); | 5513 ASSERT(lookup_.IsField()); |
| 5498 if (!info->lookup_.IsField()) return false; | 5514 if (!info->lookup_.IsField()) return false; |
| 5499 | 5515 |
| 5500 Representation r = access_.representation(); | 5516 Representation r = access_.representation(); |
| 5501 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; | 5517 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; |
| 5502 if (info->access_.offset() != access_.offset()) return false; | 5518 if (info->access_.offset() != access_.offset()) return false; |
| 5503 if (info->access_.IsInobject() != access_.IsInobject()) return false; | 5519 if (info->access_.IsInobject() != access_.IsInobject()) return false; |
| 5504 info->GeneralizeRepresentation(r); | 5520 info->GeneralizeRepresentation(r); |
| 5505 return true; | 5521 return true; |
| 5506 } | 5522 } |
| 5507 | 5523 |
| 5508 | 5524 |
| 5509 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { | 5525 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { |
| 5510 map_->LookupDescriptor(NULL, *name_, &lookup_); | 5526 if (!type_->IsClass()) return true; |
| 5511 return LoadResult(map_); | 5527 map()->LookupDescriptor(NULL, *name_, &lookup_); |
| 5528 return LoadResult(map()); |
| 5512 } | 5529 } |
| 5513 | 5530 |
| 5514 | 5531 |
| 5515 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { | 5532 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { |
| 5516 if (lookup_.IsField()) { | 5533 if (lookup_.IsField()) { |
| 5517 access_ = HObjectAccess::ForField(map, &lookup_, name_); | 5534 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
| 5518 } else if (lookup_.IsPropertyCallbacks()) { | 5535 } else if (lookup_.IsPropertyCallbacks()) { |
| 5519 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); | 5536 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
| 5520 if (!callback->IsAccessorPair()) return false; | 5537 if (!callback->IsAccessorPair()) return false; |
| 5521 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); | 5538 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); |
| 5522 if (!getter->IsJSFunction()) return false; | 5539 if (!getter->IsJSFunction()) return false; |
| 5523 Handle<JSFunction> accessor = handle(JSFunction::cast(getter)); | 5540 Handle<JSFunction> accessor = handle(JSFunction::cast(getter)); |
| 5524 CallOptimization call_optimization(accessor); | 5541 CallOptimization call_optimization(accessor); |
| 5525 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | 5542 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. |
| 5526 if (call_optimization.is_simple_api_call()) return false; | 5543 if (call_optimization.is_simple_api_call()) return false; |
| 5527 accessor_ = accessor; | 5544 accessor_ = accessor; |
| 5528 } else if (lookup_.IsConstant()) { | 5545 } else if (lookup_.IsConstant()) { |
| 5529 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); | 5546 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
| 5530 } | 5547 } |
| 5531 | 5548 |
| 5532 return true; | 5549 return true; |
| 5533 } | 5550 } |
| 5534 | 5551 |
| 5535 | 5552 |
| 5536 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { | 5553 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { |
| 5537 Handle<Map> map = map_; | 5554 Handle<Map> map = this->map(); |
| 5555 |
| 5538 while (map->prototype()->IsJSObject()) { | 5556 while (map->prototype()->IsJSObject()) { |
| 5539 holder_ = handle(JSObject::cast(map->prototype())); | 5557 holder_ = handle(JSObject::cast(map->prototype())); |
| 5540 if (holder_->map()->is_deprecated()) { | 5558 if (holder_->map()->is_deprecated()) { |
| 5541 JSObject::TryMigrateInstance(holder_); | 5559 JSObject::TryMigrateInstance(holder_); |
| 5542 } | 5560 } |
| 5543 map = Handle<Map>(holder_->map()); | 5561 map = Handle<Map>(holder_->map()); |
| 5544 if (!CanInlinePropertyAccess(*map)) { | 5562 if (!CanInlinePropertyAccess(IC::MapToType(map))) { |
| 5545 lookup_.NotFound(); | 5563 lookup_.NotFound(); |
| 5546 return false; | 5564 return false; |
| 5547 } | 5565 } |
| 5548 map->LookupDescriptor(*holder_, *name_, &lookup_); | 5566 map->LookupDescriptor(*holder_, *name_, &lookup_); |
| 5549 if (lookup_.IsFound()) return LoadResult(map); | 5567 if (lookup_.IsFound()) return LoadResult(map); |
| 5550 } | 5568 } |
| 5551 lookup_.NotFound(); | 5569 lookup_.NotFound(); |
| 5552 return true; | 5570 return true; |
| 5553 } | 5571 } |
| 5554 | 5572 |
| 5555 | 5573 |
| 5556 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { | 5574 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { |
| 5557 if (!CanInlinePropertyAccess(*map_)) return IsStringLength(); | 5575 if (!CanInlinePropertyAccess(type_)) return false; |
| 5558 if (IsJSObjectFieldAccessor()) return true; | 5576 if (IsJSObjectFieldAccessor()) return true; |
| 5559 if (!LookupDescriptor()) return false; | 5577 if (!LookupDescriptor()) return false; |
| 5560 if (lookup_.IsFound()) return true; | 5578 if (lookup_.IsFound()) return true; |
| 5561 return LookupInPrototypes(); | 5579 return LookupInPrototypes(); |
| 5562 } | 5580 } |
| 5563 | 5581 |
| 5564 | 5582 |
| 5565 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( | 5583 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( |
| 5566 SmallMapList* types) { | 5584 SmallMapList* types) { |
| 5567 ASSERT(map_.is_identical_to(types->first())); | 5585 ASSERT(type_->Is(IC::MapToType(types->first()))); |
| 5568 if (!CanLoadMonomorphic()) return false; | 5586 if (!CanLoadMonomorphic()) return false; |
| 5569 if (types->length() > kMaxLoadPolymorphism) return false; | 5587 if (types->length() > kMaxLoadPolymorphism) return false; |
| 5570 | 5588 |
| 5571 if (IsStringLength()) { | |
| 5572 for (int i = 1; i < types->length(); ++i) { | |
| 5573 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | |
| 5574 } | |
| 5575 return true; | |
| 5576 } | |
| 5577 | |
| 5578 if (IsArrayLength()) { | 5589 if (IsArrayLength()) { |
| 5579 bool is_fast = IsFastElementsKind(map_->elements_kind()); | 5590 bool is_fast = IsFastElementsKind(map()->elements_kind()); |
| 5580 for (int i = 1; i < types->length(); ++i) { | 5591 for (int i = 1; i < types->length(); ++i) { |
| 5581 Handle<Map> test_map = types->at(i); | 5592 Handle<Map> test_map = types->at(i); |
| 5582 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; | 5593 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; |
| 5583 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { | 5594 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { |
| 5584 return false; | 5595 return false; |
| 5585 } | 5596 } |
| 5586 } | 5597 } |
| 5587 return true; | 5598 return true; |
| 5588 } | 5599 } |
| 5589 | 5600 |
| 5590 if (IsJSObjectFieldAccessor()) { | 5601 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
| 5591 InstanceType instance_type = map_->instance_type(); | 5602 if (GetJSObjectFieldAccess(&access)) { |
| 5592 for (int i = 1; i < types->length(); ++i) { | 5603 for (int i = 1; i < types->length(); ++i) { |
| 5593 if (types->at(i)->instance_type() != instance_type) return false; | 5604 PropertyAccessInfo test_info( |
| 5605 builder_, IC::MapToType(types->at(i)), name_); |
| 5606 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default |
| 5607 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; |
| 5608 if (!access.Equals(test_access)) return false; |
| 5594 } | 5609 } |
| 5595 return true; | 5610 return true; |
| 5596 } | 5611 } |
| 5597 | 5612 |
| 5613 // Currently only handle HeapType::Number as a polymorphic case. |
| 5614 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5615 // instruction. |
| 5616 if (type_->Is(HeapType::Number())) return false; |
| 5617 |
| 5598 for (int i = 1; i < types->length(); ++i) { | 5618 for (int i = 1; i < types->length(); ++i) { |
| 5599 PropertyAccessInfo test_info(isolate(), types->at(i), name_); | 5619 PropertyAccessInfo test_info(builder_, IC::MapToType(types->at(i)), name_); |
| 5600 if (!test_info.IsCompatibleForLoad(this)) return false; | 5620 if (!test_info.IsCompatibleForLoad(this)) return false; |
| 5601 } | 5621 } |
| 5602 | 5622 |
| 5603 return true; | 5623 return true; |
| 5604 } | 5624 } |
| 5605 | 5625 |
| 5606 | 5626 |
| 5627 static bool NeedsWrappingFor(Handle<HeapType> type, Handle<JSFunction> target) { |
| 5628 return type->Is(HeapType::NumberOrString()) && |
| 5629 target->shared()->is_classic_mode() && |
| 5630 !target->shared()->native(); |
| 5631 } |
| 5632 |
| 5633 |
| 5607 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( | 5634 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( |
| 5608 PropertyAccessInfo* info, | 5635 PropertyAccessInfo* info, |
| 5609 HValue* object, | 5636 HValue* object, |
| 5610 HInstruction* checked_object, | 5637 HValue* checked_object, |
| 5611 BailoutId ast_id, | 5638 BailoutId ast_id, |
| 5612 BailoutId return_id, | 5639 BailoutId return_id, |
| 5613 bool can_inline_accessor) { | 5640 bool can_inline_accessor) { |
| 5614 | 5641 |
| 5615 HObjectAccess access = HObjectAccess::ForMap(); // bogus default | 5642 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
| 5616 if (info->GetJSObjectFieldAccess(&access)) { | 5643 if (info->GetJSObjectFieldAccess(&access)) { |
| 5617 return New<HLoadNamedField>( | 5644 return New<HLoadNamedField>( |
| 5618 checked_object, static_cast<HValue*>(NULL), access); | 5645 checked_object, static_cast<HValue*>(NULL), access); |
| 5619 } | 5646 } |
| 5620 | 5647 |
| 5621 HValue* checked_holder = checked_object; | 5648 HValue* checked_holder = checked_object; |
| 5622 if (info->has_holder()) { | 5649 if (info->has_holder()) { |
| 5623 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); | 5650 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); |
| 5624 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); | 5651 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); |
| 5625 } | 5652 } |
| 5626 | 5653 |
| 5627 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); | 5654 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); |
| 5628 | 5655 |
| 5629 if (info->lookup()->IsField()) { | 5656 if (info->lookup()->IsField()) { |
| 5630 return BuildLoadNamedField(checked_holder, info->access()); | 5657 return BuildLoadNamedField(checked_holder, info->access()); |
| 5631 } | 5658 } |
| 5632 | 5659 |
| 5633 if (info->lookup()->IsPropertyCallbacks()) { | 5660 if (info->lookup()->IsPropertyCallbacks()) { |
| 5634 Push(checked_object); | 5661 if (NeedsWrappingFor(info->type(), info->accessor())) { |
| 5635 if (FLAG_inline_accessors && | 5662 return New<HLoadNamedGeneric>(checked_object, info->name()); |
| 5636 can_inline_accessor && | 5663 // HValue* function = Add<HConstant>(info->accessor()); |
| 5637 TryInlineGetter(info->accessor(), ast_id, return_id)) { | 5664 // Add<HPushArgument>(checked_object); |
| 5638 return NULL; | 5665 // return New<HCallFunction>(function, 1, WRAP_AND_CALL); |
| 5666 } else { |
| 5667 Push(checked_object); |
| 5668 if (FLAG_inline_accessors && |
| 5669 can_inline_accessor && |
| 5670 TryInlineGetter(info->accessor(), ast_id, return_id)) { |
| 5671 return NULL; |
| 5672 } |
| 5673 Add<HPushArgument>(Pop()); |
| 5674 return BuildCallConstantFunction(info->accessor(), 1); |
| 5639 } | 5675 } |
| 5640 Add<HPushArgument>(Pop()); | |
| 5641 return BuildCallConstantFunction(info->accessor(), 1); | |
| 5642 } | 5676 } |
| 5643 | 5677 |
| 5644 ASSERT(info->lookup()->IsConstant()); | 5678 ASSERT(info->lookup()->IsConstant()); |
| 5645 return New<HConstant>(info->constant()); | 5679 return New<HConstant>(info->constant()); |
| 5646 } | 5680 } |
| 5647 | 5681 |
| 5648 | 5682 |
| 5649 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 5683 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
| 5650 BailoutId ast_id, | 5684 BailoutId ast_id, |
| 5651 BailoutId return_id, | 5685 BailoutId return_id, |
| 5652 HValue* object, | 5686 HValue* object, |
| 5653 SmallMapList* types, | 5687 SmallMapList* types, |
| 5654 Handle<String> name) { | 5688 Handle<String> name) { |
| 5655 // Something did not match; must use a polymorphic load. | 5689 // Something did not match; must use a polymorphic load. |
| 5656 int count = 0; | 5690 int count = 0; |
| 5657 HBasicBlock* join = NULL; | 5691 HBasicBlock* join = NULL; |
| 5692 HBasicBlock* number_block = NULL; |
| 5693 |
| 5694 bool handle_smi = false; |
| 5658 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5695 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 5659 PropertyAccessInfo info(isolate(), types->at(i), name); | 5696 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
| 5660 if (info.CanLoadMonomorphic()) { | 5697 if (info.CanLoadMonomorphic()) { |
| 5661 if (count == 0) { | 5698 count++; |
| 5662 BuildCheckHeapObject(object); | 5699 if (info.type()->Is(HeapType::Number())) { |
| 5663 join = graph()->CreateBasicBlock(); | 5700 handle_smi = true; |
| 5701 break; |
| 5664 } | 5702 } |
| 5665 ++count; | |
| 5666 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
| 5667 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
| 5668 HCompareMap* compare = New<HCompareMap>( | |
| 5669 object, info.map(), if_true, if_false); | |
| 5670 FinishCurrentBlock(compare); | |
| 5671 | |
| 5672 set_current_block(if_true); | |
| 5673 | |
| 5674 HInstruction* load = BuildLoadMonomorphic( | |
| 5675 &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); | |
| 5676 if (load == NULL) { | |
| 5677 if (HasStackOverflow()) return; | |
| 5678 } else { | |
| 5679 if (!load->IsLinked()) { | |
| 5680 AddInstruction(load); | |
| 5681 } | |
| 5682 if (!ast_context()->IsEffect()) Push(load); | |
| 5683 } | |
| 5684 | |
| 5685 if (current_block() != NULL) Goto(join); | |
| 5686 set_current_block(if_false); | |
| 5687 } | 5703 } |
| 5688 } | 5704 } |
| 5689 | 5705 |
| 5706 count = 0; |
| 5707 bool handled_string = false; |
| 5708 HControlInstruction* smi_check = NULL; |
| 5709 |
| 5710 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 5711 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
| 5712 if (info.type()->Is(HeapType::String())) { |
| 5713 if (handled_string) continue; |
| 5714 handled_string = true; |
| 5715 } |
| 5716 if (!info.CanLoadMonomorphic()) continue; |
| 5717 |
| 5718 if (count == 0) { |
| 5719 join = graph()->CreateBasicBlock(); |
| 5720 if (handle_smi) { |
| 5721 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 5722 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 5723 number_block = graph()->CreateBasicBlock(); |
| 5724 smi_check = New<HIsSmiAndBranch>( |
| 5725 object, empty_smi_block, not_smi_block); |
| 5726 FinishCurrentBlock(smi_check); |
| 5727 Goto(empty_smi_block, number_block); |
| 5728 set_current_block(not_smi_block); |
| 5729 } else { |
| 5730 BuildCheckHeapObject(object); |
| 5731 } |
| 5732 } |
| 5733 ++count; |
| 5734 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5735 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5736 HUnaryControlInstruction* compare; |
| 5737 |
| 5738 HValue* dependency; |
| 5739 if (info.type()->Is(HeapType::Number())) { |
| 5740 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 5741 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false); |
| 5742 dependency = smi_check; |
| 5743 } else if (info.type()->Is(HeapType::String())) { |
| 5744 compare = New<HIsStringAndBranch>(object, if_true, if_false); |
| 5745 dependency = compare; |
| 5746 } else { |
| 5747 compare = New<HCompareMap>(object, info.map(), if_true, if_false); |
| 5748 dependency = compare; |
| 5749 } |
| 5750 FinishCurrentBlock(compare); |
| 5751 |
| 5752 if (info.type()->Is(HeapType::Number())) { |
| 5753 Goto(if_true, number_block); |
| 5754 if_true = number_block; |
| 5755 number_block->SetJoinId(ast_id); |
| 5756 } |
| 5757 |
| 5758 set_current_block(if_true); |
| 5759 |
| 5760 HInstruction* load = BuildLoadMonomorphic( |
| 5761 &info, object, dependency, ast_id, |
| 5762 return_id, FLAG_polymorphic_inlining); |
| 5763 if (load == NULL) { |
| 5764 if (HasStackOverflow()) return; |
| 5765 } else { |
| 5766 if (!load->IsLinked()) { |
| 5767 AddInstruction(load); |
| 5768 } |
| 5769 if (!ast_context()->IsEffect()) Push(load); |
| 5770 } |
| 5771 |
| 5772 if (current_block() != NULL) Goto(join); |
| 5773 set_current_block(if_false); |
| 5774 } |
| 5775 |
| 5690 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5776 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 5691 // know about and do not want to handle ones we've never seen. Otherwise | 5777 // know about and do not want to handle ones we've never seen. Otherwise |
| 5692 // use a generic IC. | 5778 // use a generic IC. |
| 5693 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5779 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 5694 // Because the deopt may be the only path in the polymorphic load, make sure | 5780 // Because the deopt may be the only path in the polymorphic load, make sure |
| 5695 // that the environment stack matches the depth on deopt that it otherwise | 5781 // that the environment stack matches the depth on deopt that it otherwise |
| 5696 // would have had after a successful load. | 5782 // would have had after a successful load. |
| 5697 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 5783 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
| 5698 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | 5784 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); |
| 5699 } else { | 5785 } else { |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5861 HValue* receiver, | 5947 HValue* receiver, |
| 5862 SmallMapList** t) { | 5948 SmallMapList** t) { |
| 5863 SmallMapList* types = expr->GetReceiverTypes(); | 5949 SmallMapList* types = expr->GetReceiverTypes(); |
| 5864 *t = types; | 5950 *t = types; |
| 5865 bool monomorphic = expr->IsMonomorphic(); | 5951 bool monomorphic = expr->IsMonomorphic(); |
| 5866 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { | 5952 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { |
| 5867 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); | 5953 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); |
| 5868 types->FilterForPossibleTransitions(root_map); | 5954 types->FilterForPossibleTransitions(root_map); |
| 5869 monomorphic = types->length() == 1; | 5955 monomorphic = types->length() == 1; |
| 5870 } | 5956 } |
| 5871 return monomorphic && CanInlinePropertyAccess(*types->first()); | 5957 return monomorphic && CanInlinePropertyAccess(IC::MapToType(types->first())); |
| 5872 } | 5958 } |
| 5873 | 5959 |
| 5874 | 5960 |
| 5875 void HOptimizedGraphBuilder::BuildStore(Expression* expr, | 5961 void HOptimizedGraphBuilder::BuildStore(Expression* expr, |
| 5876 Property* prop, | 5962 Property* prop, |
| 5877 BailoutId ast_id, | 5963 BailoutId ast_id, |
| 5878 BailoutId return_id, | 5964 BailoutId return_id, |
| 5879 bool is_uninitialized) { | 5965 bool is_uninitialized) { |
| 5880 HValue* value = environment()->ExpressionStackAt(0); | 5966 HValue* value = environment()->ExpressionStackAt(0); |
| 5881 | 5967 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 5908 HInstruction* instr = NULL; | 5994 HInstruction* instr = NULL; |
| 5909 | 5995 |
| 5910 SmallMapList* types; | 5996 SmallMapList* types; |
| 5911 bool monomorphic = ComputeReceiverTypes(expr, object, &types); | 5997 bool monomorphic = ComputeReceiverTypes(expr, object, &types); |
| 5912 | 5998 |
| 5913 if (monomorphic) { | 5999 if (monomorphic) { |
| 5914 Handle<Map> map = types->first(); | 6000 Handle<Map> map = types->first(); |
| 5915 Handle<JSFunction> setter; | 6001 Handle<JSFunction> setter; |
| 5916 Handle<JSObject> holder; | 6002 Handle<JSObject> holder; |
| 5917 if (LookupSetter(map, name, &setter, &holder)) { | 6003 if (LookupSetter(map, name, &setter, &holder)) { |
| 5918 AddCheckConstantFunction(holder, object, map); | 6004 AddCheckMap(object, map); |
| 5919 if (FLAG_inline_accessors && | 6005 AddCheckPrototypeMaps(holder, map); |
| 5920 TryInlineSetter(setter, ast_id, return_id, value)) { | 6006 bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter); |
| 6007 bool try_inline = FLAG_inline_accessors && !needs_wrapping; |
| 6008 if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) { |
| 5921 return; | 6009 return; |
| 5922 } | 6010 } |
| 5923 Drop(2); | 6011 Drop(2); |
| 5924 Add<HPushArgument>(object); | 6012 if (needs_wrapping) { |
| 5925 Add<HPushArgument>(value); | 6013 instr = BuildStoreNamedGeneric(object, name, value); |
| 5926 instr = BuildCallConstantFunction(setter, 2); | 6014 } else { |
| 6015 Add<HPushArgument>(object); |
| 6016 Add<HPushArgument>(value); |
| 6017 instr = BuildCallConstantFunction(setter, 2); |
| 6018 } |
| 5927 } else { | 6019 } else { |
| 5928 Drop(2); | 6020 Drop(2); |
| 5929 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 6021 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
| 5930 name, | 6022 name, |
| 5931 value, | 6023 value, |
| 5932 map)); | 6024 map)); |
| 5933 } | 6025 } |
| 5934 } else if (types != NULL && types->length() > 1) { | 6026 } else if (types != NULL && types->length() > 1) { |
| 5935 Drop(2); | 6027 Drop(2); |
| 5936 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); | 6028 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); |
| (...skipping 832 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6769 | 6861 |
| 6770 } else if (expr->key()->IsPropertyName()) { | 6862 } else if (expr->key()->IsPropertyName()) { |
| 6771 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 6863 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 6772 HValue* object = Pop(); | 6864 HValue* object = Pop(); |
| 6773 | 6865 |
| 6774 SmallMapList* types; | 6866 SmallMapList* types; |
| 6775 ComputeReceiverTypes(expr, object, &types); | 6867 ComputeReceiverTypes(expr, object, &types); |
| 6776 ASSERT(types != NULL); | 6868 ASSERT(types != NULL); |
| 6777 | 6869 |
| 6778 if (types->length() > 0) { | 6870 if (types->length() > 0) { |
| 6779 PropertyAccessInfo info(isolate(), types->first(), name); | 6871 PropertyAccessInfo info(this, IC::MapToType(types->first()), name); |
| 6780 if (!info.CanLoadAsMonomorphic(types)) { | 6872 if (!info.CanLoadAsMonomorphic(types)) { |
| 6781 return HandlePolymorphicLoadNamedField( | 6873 return HandlePolymorphicLoadNamedField( |
| 6782 ast_id, expr->LoadId(), object, types, name); | 6874 ast_id, expr->LoadId(), object, types, name); |
| 6783 } | 6875 } |
| 6784 | 6876 |
| 6877 HValue* checked_object; |
| 6878 // HeapType::Number() is only supported by polymorphic load/call handling. |
| 6879 ASSERT(!info.type()->Is(HeapType::Number())); |
| 6785 BuildCheckHeapObject(object); | 6880 BuildCheckHeapObject(object); |
| 6786 HInstruction* checked_object; | |
| 6787 if (AreStringTypes(types)) { | 6881 if (AreStringTypes(types)) { |
| 6788 checked_object = | 6882 checked_object = |
| 6789 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); | 6883 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); |
| 6790 } else { | 6884 } else { |
| 6791 checked_object = Add<HCheckMaps>(object, types); | 6885 checked_object = Add<HCheckMaps>(object, types); |
| 6792 } | 6886 } |
| 6793 instr = BuildLoadMonomorphic( | 6887 instr = BuildLoadMonomorphic( |
| 6794 &info, object, checked_object, ast_id, expr->LoadId()); | 6888 &info, object, checked_object, ast_id, expr->LoadId()); |
| 6795 if (instr == NULL) return; | 6889 if (instr == NULL) return; |
| 6796 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); | 6890 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7003 } | 7097 } |
| 7004 | 7098 |
| 7005 | 7099 |
| 7006 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( | 7100 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( |
| 7007 Call* expr, | 7101 Call* expr, |
| 7008 HValue* receiver, | 7102 HValue* receiver, |
| 7009 SmallMapList* types, | 7103 SmallMapList* types, |
| 7010 Handle<String> name) { | 7104 Handle<String> name) { |
| 7011 if (types->length() > kMaxCallPolymorphism) return false; | 7105 if (types->length() > kMaxCallPolymorphism) return false; |
| 7012 | 7106 |
| 7013 PropertyAccessInfo info(isolate(), types->at(0), name); | 7107 PropertyAccessInfo info(this, IC::MapToType(types->at(0)), name); |
| 7014 if (!info.CanLoadAsMonomorphic(types)) return false; | 7108 if (!info.CanLoadAsMonomorphic(types)) return false; |
| 7015 if (!expr->ComputeTarget(info.map(), name)) return false; | 7109 if (!expr->ComputeTarget(info.map(), name)) return false; |
| 7016 | 7110 |
| 7017 BuildCheckHeapObject(receiver); | 7111 BuildCheckHeapObject(receiver); |
| 7018 Add<HCheckMaps>(receiver, types); | 7112 Add<HCheckMaps>(receiver, types); |
| 7019 AddCheckPrototypeMaps(expr->holder(), info.map()); | 7113 AddCheckPrototypeMaps(expr->holder(), info.map()); |
| 7020 if (FLAG_trace_inlining) { | 7114 if (FLAG_trace_inlining) { |
| 7021 Handle<JSFunction> caller = current_info()->closure(); | 7115 Handle<JSFunction> caller = current_info()->closure(); |
| 7022 SmartArrayPointer<char> caller_name = | 7116 SmartArrayPointer<char> caller_name = |
| 7023 caller->shared()->DebugName()->ToCString(); | 7117 caller->shared()->DebugName()->ToCString(); |
| (...skipping 4237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11261 if (ShouldProduceTraceOutput()) { | 11355 if (ShouldProduceTraceOutput()) { |
| 11262 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11356 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 11263 } | 11357 } |
| 11264 | 11358 |
| 11265 #ifdef DEBUG | 11359 #ifdef DEBUG |
| 11266 graph_->Verify(false); // No full verify. | 11360 graph_->Verify(false); // No full verify. |
| 11267 #endif | 11361 #endif |
| 11268 } | 11362 } |
| 11269 | 11363 |
| 11270 } } // namespace v8::internal | 11364 } } // namespace v8::internal |
| OLD | NEW |