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 |