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 4044 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4055 *accessors = Handle<AccessorPair>::cast(callback); | 4055 *accessors = Handle<AccessorPair>::cast(callback); |
4056 *holder = Handle<JSObject>(lookup.holder()); | 4056 *holder = Handle<JSObject>(lookup.holder()); |
4057 return true; | 4057 return true; |
4058 } | 4058 } |
4059 | 4059 |
4060 // We haven't found a JavaScript accessor anywhere. | 4060 // We haven't found a JavaScript accessor anywhere. |
4061 return false; | 4061 return false; |
4062 } | 4062 } |
4063 | 4063 |
4064 | 4064 |
4065 static bool LookupGetter(Handle<Map> map, | |
4066 Handle<String> name, | |
4067 Handle<JSFunction>* getter, | |
4068 Handle<JSObject>* holder) { | |
4069 Handle<AccessorPair> accessors; | |
4070 if (LookupAccessorPair(map, name, &accessors, holder) && | |
4071 accessors->getter()->IsJSFunction()) { | |
4072 *getter = Handle<JSFunction>(JSFunction::cast(accessors->getter())); | |
4073 return true; | |
4074 } | |
4075 return false; | |
4076 } | |
4077 | |
4078 | |
4079 static bool LookupSetter(Handle<Map> map, | 4065 static bool LookupSetter(Handle<Map> map, |
4080 Handle<String> name, | 4066 Handle<String> name, |
4081 Handle<JSFunction>* setter, | 4067 Handle<JSFunction>* setter, |
4082 Handle<JSObject>* holder) { | 4068 Handle<JSObject>* holder) { |
4083 Handle<AccessorPair> accessors; | 4069 Handle<AccessorPair> accessors; |
4084 if (LookupAccessorPair(map, name, &accessors, holder) && | 4070 if (LookupAccessorPair(map, name, &accessors, holder) && |
4085 accessors->setter()->IsJSFunction()) { | 4071 accessors->setter()->IsJSFunction()) { |
4086 *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter())); | 4072 *setter = Handle<JSFunction>(JSFunction::cast(accessors->setter())); |
4087 return true; | 4073 return true; |
4088 } | 4074 } |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4536 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 4522 if (ComputeLoadStoreField(map, name, &lookup, true)) { |
4537 HCheckMaps* checked_object = AddCheckMap(object, map); | 4523 HCheckMaps* checked_object = AddCheckMap(object, map); |
4538 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | 4524 return BuildStoreNamedField(checked_object, name, value, map, &lookup); |
4539 } | 4525 } |
4540 | 4526 |
4541 // No luck, do a generic store. | 4527 // No luck, do a generic store. |
4542 return BuildStoreNamedGeneric(object, name, value); | 4528 return BuildStoreNamedGeneric(object, name, value); |
4543 } | 4529 } |
4544 | 4530 |
4545 | 4531 |
4546 static bool CanLoadPropertyFromPrototype(Handle<Map> map, | 4532 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( |
4547 Handle<Name> name, | 4533 PropertyAccessInfo* info) { |
4548 LookupResult* lookup) { | 4534 if (!CanInlinePropertyAccess(*map_)) return false; |
4549 if (!CanInlinePropertyAccess(*map)) return false; | 4535 |
4550 map->LookupDescriptor(NULL, *name, lookup); | 4536 if (!LookupDescriptor()) return false; |
4551 if (lookup->IsFound()) return false; | 4537 |
| 4538 if (!lookup_.IsFound()) { |
| 4539 return (!info->lookup_.IsFound() || !info->holder_.is_null()) && |
| 4540 map_->prototype() == info->map_->prototype(); |
| 4541 } |
| 4542 |
| 4543 if (lookup_.IsPropertyCallbacks()) { |
| 4544 return accessor_.is_identical_to(info->accessor_); |
| 4545 } |
| 4546 |
| 4547 if (lookup_.IsConstant()) { |
| 4548 return constant_.is_identical_to(info->constant_); |
| 4549 } |
| 4550 |
| 4551 ASSERT(lookup_.IsField()); |
| 4552 if (!info->lookup_.IsField()) return false; |
| 4553 |
| 4554 Representation r = access_.representation(); |
| 4555 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; |
| 4556 if (info->access_.offset() != access_.offset()) return false; |
| 4557 if (info->access_.IsInobject() != access_.IsInobject()) return false; |
| 4558 info->GeneralizeRepresentation(r); |
4552 return true; | 4559 return true; |
4553 } | 4560 } |
4554 | 4561 |
4555 | 4562 |
4556 HInstruction* HOptimizedGraphBuilder::TryLoadPolymorphicAsMonomorphic( | 4563 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { |
4557 HValue* object, | 4564 map_->LookupDescriptor(NULL, *name_, &lookup_); |
4558 SmallMapList* types, | 4565 return LoadResult(map_); |
4559 Handle<String> name) { | |
4560 // Use monomorphic load if property lookup results in the same field index | |
4561 // for all maps. Requires special map check on the set of all handled maps. | |
4562 if (types->length() > kMaxLoadPolymorphism) return NULL; | |
4563 | |
4564 LookupResult lookup(isolate()); | |
4565 int count; | |
4566 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | |
4567 for (count = 0; count < types->length(); ++count) { | |
4568 Handle<Map> map = types->at(count); | |
4569 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; | |
4570 | |
4571 HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); | |
4572 | |
4573 if (count == 0) { | |
4574 // First time through the loop; set access and representation. | |
4575 access = new_access; | |
4576 } else if (!access.representation().IsCompatibleForLoad( | |
4577 new_access.representation())) { | |
4578 // Representations did not match. | |
4579 break; | |
4580 } else if (access.offset() != new_access.offset()) { | |
4581 // Offsets did not match. | |
4582 break; | |
4583 } else if (access.IsInobject() != new_access.IsInobject()) { | |
4584 // In-objectness did not match. | |
4585 break; | |
4586 } | |
4587 access = access.WithRepresentation( | |
4588 access.representation().generalize(new_access.representation())); | |
4589 } | |
4590 | |
4591 if (count == types->length()) { | |
4592 // Everything matched; can use monomorphic load. | |
4593 BuildCheckHeapObject(object); | |
4594 HCheckMaps* checked_object = Add<HCheckMaps>(object, types); | |
4595 return BuildLoadNamedField(checked_object, access); | |
4596 } | |
4597 | |
4598 if (count != 0) return NULL; | |
4599 | |
4600 // Second chance: the property is on the prototype and all maps have the | |
4601 // same prototype. | |
4602 Handle<Map> map(types->at(0)); | |
4603 if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return NULL; | |
4604 | |
4605 Handle<Object> prototype(map->prototype(), isolate()); | |
4606 for (count = 1; count < types->length(); ++count) { | |
4607 Handle<Map> test_map(types->at(count)); | |
4608 if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return NULL; | |
4609 if (test_map->prototype() != *prototype) return NULL; | |
4610 } | |
4611 | |
4612 LookupInPrototypes(map, name, &lookup); | |
4613 if (!lookup.IsField()) return NULL; | |
4614 | |
4615 BuildCheckHeapObject(object); | |
4616 Add<HCheckMaps>(object, types); | |
4617 | |
4618 Handle<JSObject> holder(lookup.holder()); | |
4619 Handle<Map> holder_map(holder->map()); | |
4620 HValue* checked_holder = BuildCheckPrototypeMaps( | |
4621 Handle<JSObject>::cast(prototype), holder); | |
4622 return BuildLoadNamedField(checked_holder, | |
4623 HObjectAccess::ForField(holder_map, &lookup, name)); | |
4624 } | 4566 } |
4625 | 4567 |
4626 | 4568 |
4627 // Returns true if an instance of this map can never find a property with this | 4569 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { |
4628 // name in its prototype chain. This means all prototypes up to the top are | 4570 if (lookup_.IsField()) { |
4629 // fast and don't have the name in them. It would be good if we could optimize | 4571 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
4630 // polymorphic loads where the property is sometimes found in the prototype | 4572 } else if (lookup_.IsPropertyCallbacks()) { |
4631 // chain. | 4573 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
4632 static bool PrototypeChainCanNeverResolve( | 4574 if (!callback->IsAccessorPair()) return false; |
4633 Handle<Map> map, Handle<String> name) { | 4575 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); |
4634 Isolate* isolate = map->GetIsolate(); | 4576 if (!getter->IsJSFunction()) return false; |
4635 Object* current = map->prototype(); | 4577 accessor_ = handle(JSFunction::cast(getter)); |
4636 while (current != isolate->heap()->null_value()) { | 4578 } else if (lookup_.IsConstant()) { |
4637 if (current->IsJSGlobalProxy() || | 4579 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
4638 current->IsGlobalObject() || | 4580 } |
4639 !current->IsJSObject() || | 4581 |
4640 !CanInlinePropertyAccess(JSObject::cast(current)->map()) || | 4582 return true; |
4641 JSObject::cast(current)->IsAccessCheckNeeded()) { | 4583 } |
| 4584 |
| 4585 |
| 4586 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { |
| 4587 Handle<Map> map = map_; |
| 4588 while (map->prototype()->IsJSObject()) { |
| 4589 holder_ = handle(JSObject::cast(map->prototype())); |
| 4590 map = Handle<Map>(holder_->map()); |
| 4591 if (!CanInlinePropertyAccess(*map)) { |
| 4592 lookup_.NotFound(); |
4642 return false; | 4593 return false; |
4643 } | 4594 } |
| 4595 map->LookupDescriptor(*holder_, *name_, &lookup_); |
| 4596 if (lookup_.IsFound()) return LoadResult(map); |
| 4597 } |
| 4598 lookup_.NotFound(); |
| 4599 return true; |
| 4600 } |
4644 | 4601 |
4645 LookupResult lookup(isolate); | 4602 |
4646 Map* map = JSObject::cast(current)->map(); | 4603 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { |
4647 map->LookupDescriptor(NULL, *name, &lookup); | 4604 if (!CanInlinePropertyAccess(*map_)) return IsStringLength(); |
4648 if (lookup.IsFound()) return false; | 4605 if (IsArrayLength()) return true; |
4649 if (!lookup.IsCacheable()) return false; | 4606 if (!LookupDescriptor()) return false; |
4650 current = JSObject::cast(current)->GetPrototype(); | 4607 if (lookup_.IsFound()) return true; |
| 4608 return LookupInPrototypes(); |
| 4609 } |
| 4610 |
| 4611 |
| 4612 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( |
| 4613 SmallMapList* types) { |
| 4614 ASSERT(map_.is_identical_to(types->first())); |
| 4615 if (!CanLoadMonomorphic()) return false; |
| 4616 if (types->length() > kMaxLoadPolymorphism) return false; |
| 4617 |
| 4618 if (IsStringLength()) { |
| 4619 for (int i = 1; i < types->length(); ++i) { |
| 4620 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; |
| 4621 } |
| 4622 return true; |
4651 } | 4623 } |
| 4624 |
| 4625 if (IsArrayLength()) { |
| 4626 bool is_fast = IsFastElementsKind(map_->elements_kind()); |
| 4627 for (int i = 1; i < types->length(); ++i) { |
| 4628 Handle<Map> test_map = types->at(i); |
| 4629 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; |
| 4630 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { |
| 4631 return false; |
| 4632 } |
| 4633 } |
| 4634 return true; |
| 4635 } |
| 4636 |
| 4637 for (int i = 1; i < types->length(); ++i) { |
| 4638 PropertyAccessInfo test_info(isolate(), types->at(i), name_); |
| 4639 if (!test_info.IsCompatibleForLoad(this)) return false; |
| 4640 } |
| 4641 |
4652 return true; | 4642 return true; |
4653 } | 4643 } |
4654 | 4644 |
4655 | 4645 |
| 4646 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( |
| 4647 PropertyAccessInfo* info, |
| 4648 HValue* object, |
| 4649 HInstruction* checked_object, |
| 4650 BailoutId ast_id, |
| 4651 BailoutId return_id, |
| 4652 bool can_inline_accessor) { |
| 4653 if (info->IsStringLength()) { |
| 4654 return New<HLoadNamedField>( |
| 4655 checked_object, HObjectAccess::ForStringLength()); |
| 4656 } |
| 4657 |
| 4658 if (info->IsArrayLength()) { |
| 4659 return New<HLoadNamedField>( |
| 4660 checked_object, HObjectAccess::ForArrayLength( |
| 4661 info->map()->elements_kind())); |
| 4662 } |
| 4663 |
| 4664 HValue* checked_holder = checked_object; |
| 4665 if (info->has_holder()) { |
| 4666 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); |
| 4667 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); |
| 4668 } |
| 4669 |
| 4670 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); |
| 4671 |
| 4672 if (info->lookup()->IsField()) { |
| 4673 return BuildLoadNamedField(checked_holder, info->access()); |
| 4674 } |
| 4675 |
| 4676 if (info->lookup()->IsPropertyCallbacks()) { |
| 4677 Push(checked_object); |
| 4678 if (FLAG_inline_accessors && |
| 4679 can_inline_accessor && |
| 4680 TryInlineGetter(info->accessor(), ast_id, return_id)) { |
| 4681 return NULL; |
| 4682 } |
| 4683 Add<HPushArgument>(Pop()); |
| 4684 return new(zone()) HCallConstantFunction(info->accessor(), 1); |
| 4685 } |
| 4686 |
| 4687 ASSERT(info->lookup()->IsConstant()); |
| 4688 return New<HConstant>(info->constant()); |
| 4689 } |
| 4690 |
| 4691 |
4656 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 4692 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
4657 int position, | 4693 int position, |
4658 BailoutId ast_id, | 4694 BailoutId ast_id, |
| 4695 BailoutId return_id, |
4659 HValue* object, | 4696 HValue* object, |
4660 SmallMapList* types, | 4697 SmallMapList* types, |
4661 Handle<String> name) { | 4698 Handle<String> name) { |
4662 HInstruction* instr = TryLoadPolymorphicAsMonomorphic(object, types, name); | |
4663 if (instr != NULL) { | |
4664 instr->set_position(position); | |
4665 return ast_context()->ReturnInstruction(instr, ast_id); | |
4666 } | |
4667 | |
4668 // Something did not match; must use a polymorphic load. | 4699 // Something did not match; must use a polymorphic load. |
4669 int count = 0; | 4700 int count = 0; |
4670 HBasicBlock* join = NULL; | 4701 HBasicBlock* join = NULL; |
4671 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 4702 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
4672 Handle<Map> map = types->at(i); | 4703 PropertyAccessInfo info(isolate(), types->at(i), name); |
4673 LookupResult lookup(isolate()); | 4704 if (info.CanLoadMonomorphic()) { |
4674 if (ComputeLoadStoreField(map, name, &lookup, false) || | |
4675 (lookup.IsCacheable() && | |
4676 CanInlinePropertyAccess(*map) && | |
4677 (lookup.IsConstant() || | |
4678 (!lookup.IsFound() && | |
4679 PrototypeChainCanNeverResolve(map, name))))) { | |
4680 if (count == 0) { | 4705 if (count == 0) { |
4681 BuildCheckHeapObject(object); | 4706 BuildCheckHeapObject(object); |
4682 join = graph()->CreateBasicBlock(); | 4707 join = graph()->CreateBasicBlock(); |
4683 } | 4708 } |
4684 ++count; | 4709 ++count; |
4685 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 4710 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
4686 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 4711 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
4687 HCompareMap* compare = | 4712 HCompareMap* compare = new(zone()) HCompareMap( |
4688 new(zone()) HCompareMap(object, map, if_true, if_false); | 4713 object, info.map(), if_true, if_false); |
4689 current_block()->Finish(compare); | 4714 current_block()->Finish(compare); |
4690 | 4715 |
4691 set_current_block(if_true); | 4716 set_current_block(if_true); |
4692 | 4717 |
4693 // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. | 4718 HInstruction* load = BuildLoadMonomorphic( |
4694 if (lookup.IsField()) { | 4719 &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); |
4695 HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); | 4720 if (load == NULL) { |
4696 HLoadNamedField* load = BuildLoadNamedField(compare, access); | 4721 if (HasStackOverflow()) return; |
4697 load->set_position(position); | 4722 } else { |
4698 AddInstruction(load); | 4723 if (!load->IsLinked()) { |
| 4724 load->set_position(position); |
| 4725 AddInstruction(load); |
| 4726 } |
4699 if (!ast_context()->IsEffect()) Push(load); | 4727 if (!ast_context()->IsEffect()) Push(load); |
4700 } else if (lookup.IsConstant()) { | |
4701 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | |
4702 HConstant* hconstant = Add<HConstant>(constant); | |
4703 if (!ast_context()->IsEffect()) Push(hconstant); | |
4704 } else { | |
4705 ASSERT(!lookup.IsFound()); | |
4706 if (map->prototype()->IsJSObject()) { | |
4707 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
4708 Handle<JSObject> holder = prototype; | |
4709 while (holder->map()->prototype()->IsJSObject()) { | |
4710 holder = handle(JSObject::cast(holder->map()->prototype())); | |
4711 } | |
4712 BuildCheckPrototypeMaps(prototype, holder); | |
4713 } | |
4714 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); | |
4715 } | 4728 } |
4716 | 4729 |
4717 current_block()->Goto(join); | 4730 if (current_block() != NULL) current_block()->Goto(join); |
4718 set_current_block(if_false); | 4731 set_current_block(if_false); |
4719 } | 4732 } |
4720 } | 4733 } |
4721 | 4734 |
4722 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 4735 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
4723 // know about and do not want to handle ones we've never seen. Otherwise | 4736 // know about and do not want to handle ones we've never seen. Otherwise |
4724 // use a generic IC. | 4737 // use a generic IC. |
4725 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 4738 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
4726 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | 4739 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); |
4727 } else { | 4740 } else { |
(...skipping 23 matching lines...) Expand all Loading... |
4751 int position, | 4764 int position, |
4752 BailoutId assignment_id, | 4765 BailoutId assignment_id, |
4753 HValue* object, | 4766 HValue* object, |
4754 HValue* value, | 4767 HValue* value, |
4755 SmallMapList* types, | 4768 SmallMapList* types, |
4756 Handle<String> name) { | 4769 Handle<String> name) { |
4757 // Use monomorphic store if property lookup results in the same field index | 4770 // Use monomorphic store if property lookup results in the same field index |
4758 // for all maps. Requires special map check on the set of all handled maps. | 4771 // for all maps. Requires special map check on the set of all handled maps. |
4759 if (types->length() > kMaxStorePolymorphism) return false; | 4772 if (types->length() > kMaxStorePolymorphism) return false; |
4760 | 4773 |
4761 // TODO(verwaest): Merge the checking logic with the code in | |
4762 // TryLoadPolymorphicAsMonomorphic. | |
4763 LookupResult lookup(isolate()); | 4774 LookupResult lookup(isolate()); |
4764 int count; | 4775 int count; |
4765 Representation representation = Representation::None(); | 4776 Representation representation = Representation::None(); |
4766 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | 4777 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. |
4767 for (count = 0; count < types->length(); ++count) { | 4778 for (count = 0; count < types->length(); ++count) { |
4768 Handle<Map> map = types->at(count); | 4779 Handle<Map> map = types->at(count); |
4769 // Pass false to ignore transitions. | 4780 // Pass false to ignore transitions. |
4770 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; | 4781 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; |
4771 ASSERT(!map->is_observed()); | 4782 ASSERT(!map->is_observed()); |
4772 | 4783 |
(...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5351 HValue* object, | 5362 HValue* object, |
5352 Handle<Map> map, | 5363 Handle<Map> map, |
5353 Handle<JSFunction> getter, | 5364 Handle<JSFunction> getter, |
5354 Handle<JSObject> holder) { | 5365 Handle<JSObject> holder) { |
5355 AddCheckConstantFunction(holder, object, map); | 5366 AddCheckConstantFunction(holder, object, map); |
5356 Add<HPushArgument>(object); | 5367 Add<HPushArgument>(object); |
5357 return new(zone()) HCallConstantFunction(getter, 1); | 5368 return new(zone()) HCallConstantFunction(getter, 1); |
5358 } | 5369 } |
5359 | 5370 |
5360 | 5371 |
5361 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic( | |
5362 HValue* object, | |
5363 Handle<String> name, | |
5364 Handle<Map> map) { | |
5365 // Handle a load from a known field. | |
5366 ASSERT(!map->is_dictionary_map()); | |
5367 | |
5368 // Handle access to various length properties | |
5369 if (name->Equals(isolate()->heap()->length_string())) { | |
5370 if (map->instance_type() == JS_ARRAY_TYPE) { | |
5371 HCheckMaps* checked_object = AddCheckMap(object, map); | |
5372 return New<HLoadNamedField>( | |
5373 checked_object, HObjectAccess::ForArrayLength(map->elements_kind())); | |
5374 } | |
5375 } | |
5376 | |
5377 LookupResult lookup(isolate()); | |
5378 map->LookupDescriptor(NULL, *name, &lookup); | |
5379 if (lookup.IsField()) { | |
5380 HCheckMaps* checked_object = AddCheckMap(object, map); | |
5381 ASSERT(map->IsJSObjectMap()); | |
5382 return BuildLoadNamedField( | |
5383 checked_object, HObjectAccess::ForField(map, &lookup, name)); | |
5384 } | |
5385 | |
5386 // Handle a load of a constant known function. | |
5387 if (lookup.IsConstant()) { | |
5388 AddCheckMap(object, map); | |
5389 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | |
5390 return New<HConstant>(constant); | |
5391 } | |
5392 | |
5393 if (lookup.IsFound()) { | |
5394 // Cannot handle the property, do a generic load instead. | |
5395 HValue* context = environment()->context(); | |
5396 return new(zone()) HLoadNamedGeneric(context, object, name); | |
5397 } | |
5398 | |
5399 // Handle a load from a known field somewhere in the prototype chain. | |
5400 LookupInPrototypes(map, name, &lookup); | |
5401 if (lookup.IsField()) { | |
5402 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
5403 Handle<JSObject> holder(lookup.holder()); | |
5404 Handle<Map> holder_map(holder->map()); | |
5405 AddCheckMap(object, map); | |
5406 HValue* checked_holder = BuildCheckPrototypeMaps(prototype, holder); | |
5407 return BuildLoadNamedField( | |
5408 checked_holder, HObjectAccess::ForField(holder_map, &lookup, name)); | |
5409 } | |
5410 | |
5411 // Handle a load of a constant function somewhere in the prototype chain. | |
5412 if (lookup.IsConstant()) { | |
5413 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
5414 Handle<JSObject> holder(lookup.holder()); | |
5415 Handle<Map> holder_map(holder->map()); | |
5416 AddCheckMap(object, map); | |
5417 BuildCheckPrototypeMaps(prototype, holder); | |
5418 Handle<Object> constant(lookup.GetConstantFromMap(*holder_map), isolate()); | |
5419 return New<HConstant>(constant); | |
5420 } | |
5421 | |
5422 // No luck, do a generic load. | |
5423 HValue* context = environment()->context(); | |
5424 return new(zone()) HLoadNamedGeneric(context, object, name); | |
5425 } | |
5426 | |
5427 | |
5428 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 5372 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
5429 HValue* key) { | 5373 HValue* key) { |
5430 HValue* context = environment()->context(); | 5374 HValue* context = environment()->context(); |
5431 return new(zone()) HLoadKeyedGeneric(context, object, key); | 5375 return new(zone()) HLoadKeyedGeneric(context, object, key); |
5432 } | 5376 } |
5433 | 5377 |
5434 | 5378 |
5435 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { | 5379 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { |
5436 // Loads from a "stock" fast holey double arrays can elide the hole check. | 5380 // Loads from a "stock" fast holey double arrays can elide the hole check. |
5437 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; | 5381 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5817 HValue* key, | 5761 HValue* key, |
5818 int position) { | 5762 int position) { |
5819 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); | 5763 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
5820 Push(object); | 5764 Push(object); |
5821 if (key != NULL) Push(key); | 5765 if (key != NULL) Push(key); |
5822 BuildLoad(expr, position, expr->LoadId()); | 5766 BuildLoad(expr, position, expr->LoadId()); |
5823 } | 5767 } |
5824 | 5768 |
5825 | 5769 |
5826 static bool AreStringTypes(SmallMapList* types) { | 5770 static bool AreStringTypes(SmallMapList* types) { |
5827 if (types == NULL || types->length() == 0) return false; | |
5828 for (int i = 0; i < types->length(); i++) { | 5771 for (int i = 0; i < types->length(); i++) { |
5829 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | 5772 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; |
5830 } | 5773 } |
5831 return true; | 5774 return true; |
5832 } | 5775 } |
5833 | 5776 |
5834 | 5777 |
5835 void HOptimizedGraphBuilder::BuildLoad(Property* expr, | 5778 void HOptimizedGraphBuilder::BuildLoad(Property* expr, |
5836 int position, | 5779 int position, |
5837 BailoutId ast_id) { | 5780 BailoutId ast_id) { |
5838 HInstruction* instr = NULL; | 5781 HInstruction* instr = NULL; |
5839 if (expr->IsStringAccess()) { | 5782 if (expr->IsStringAccess()) { |
5840 HValue* index = Pop(); | 5783 HValue* index = Pop(); |
5841 HValue* string = Pop(); | 5784 HValue* string = Pop(); |
5842 HValue* context = environment()->context(); | 5785 HValue* context = environment()->context(); |
5843 HInstruction* char_code = | 5786 HInstruction* char_code = |
5844 BuildStringCharCodeAt(string, index); | 5787 BuildStringCharCodeAt(string, index); |
5845 AddInstruction(char_code); | 5788 AddInstruction(char_code); |
5846 instr = HStringCharFromCode::New(zone(), context, char_code); | 5789 instr = HStringCharFromCode::New(zone(), context, char_code); |
5847 | 5790 |
5848 } else if (expr->IsFunctionPrototype()) { | 5791 } else if (expr->IsFunctionPrototype()) { |
5849 HValue* function = Pop(); | 5792 HValue* function = Pop(); |
5850 BuildCheckHeapObject(function); | 5793 BuildCheckHeapObject(function); |
5851 instr = new(zone()) HLoadFunctionPrototype(function); | 5794 instr = new(zone()) HLoadFunctionPrototype(function); |
5852 | 5795 |
5853 } else if (expr->key()->IsPropertyName()) { | 5796 } else if (expr->key()->IsPropertyName()) { |
5854 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 5797 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
5855 HValue* object = Top(); | 5798 HValue* object = Pop(); |
5856 | 5799 |
5857 SmallMapList* types; | 5800 SmallMapList* types; |
5858 bool monomorphic = ComputeReceiverTypes(expr, object, &types); | 5801 ComputeReceiverTypes(expr, object, &types); |
| 5802 ASSERT(types != NULL); |
5859 | 5803 |
5860 if (monomorphic) { | 5804 if (types->length() > 0) { |
5861 Handle<Map> map = types->first(); | 5805 PropertyAccessInfo info(isolate(), types->first(), name); |
5862 Handle<JSFunction> getter; | 5806 if (!info.CanLoadAsMonomorphic(types)) { |
5863 Handle<JSObject> holder; | 5807 return HandlePolymorphicLoadNamedField( |
5864 if (LookupGetter(map, name, &getter, &holder)) { | 5808 position, ast_id, expr->LoadId(), object, types, name); |
5865 AddCheckConstantFunction(holder, Top(), map); | 5809 } |
5866 if (FLAG_inline_accessors && | 5810 |
5867 TryInlineGetter(getter, ast_id, expr->LoadId())) { | 5811 BuildCheckHeapObject(object); |
5868 return; | 5812 HInstruction* checked_object; |
5869 } | 5813 if (AreStringTypes(types)) { |
5870 Add<HPushArgument>(Pop()); | 5814 checked_object = |
5871 instr = new(zone()) HCallConstantFunction(getter, 1); | 5815 AddInstruction(HCheckInstanceType::NewIsString(object, zone())); |
5872 } else { | 5816 } else { |
5873 instr = BuildLoadNamedMonomorphic(Pop(), name, map); | 5817 checked_object = Add<HCheckMaps>(object, types); |
5874 } | 5818 } |
5875 } else if (AreStringTypes(types) && | 5819 instr = BuildLoadMonomorphic( |
5876 name->Equals(isolate()->heap()->length_string())) { | 5820 &info, object, checked_object, ast_id, expr->LoadId()); |
5877 BuildCheckHeapObject(Pop()); | 5821 if (instr == NULL) return; |
5878 HValue* checked_object = | 5822 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
5879 AddInstruction(HCheckInstanceType::NewIsString(object, zone())); | |
5880 instr = BuildLoadStringLength(object, checked_object); | |
5881 } else if (types != NULL && types->length() > 1) { | |
5882 return HandlePolymorphicLoadNamedField( | |
5883 position, ast_id, Pop(), types, name); | |
5884 } else { | 5823 } else { |
5885 instr = BuildLoadNamedGeneric(Pop(), name, expr); | 5824 instr = BuildLoadNamedGeneric(object, name, expr); |
5886 } | 5825 } |
5887 | 5826 |
5888 } else { | 5827 } else { |
5889 HValue* key = Pop(); | 5828 HValue* key = Pop(); |
5890 HValue* obj = Pop(); | 5829 HValue* obj = Pop(); |
5891 | 5830 |
5892 bool has_side_effects = false; | 5831 bool has_side_effects = false; |
5893 HValue* load = HandleKeyedElementAccess( | 5832 HValue* load = HandleKeyedElementAccess( |
5894 obj, key, NULL, expr, ast_id, position, | 5833 obj, key, NULL, expr, ast_id, position, |
5895 false, // is_store | 5834 false, // is_store |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6010 } | 5949 } |
6011 | 5950 |
6012 | 5951 |
6013 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( | 5952 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( |
6014 Call* expr, | 5953 Call* expr, |
6015 HValue* receiver, | 5954 HValue* receiver, |
6016 SmallMapList* types, | 5955 SmallMapList* types, |
6017 Handle<String> name) { | 5956 Handle<String> name) { |
6018 if (types->length() > kMaxCallPolymorphism) return false; | 5957 if (types->length() > kMaxCallPolymorphism) return false; |
6019 | 5958 |
6020 Handle<Map> map(types->at(0)); | 5959 PropertyAccessInfo info(isolate(), types->at(0), name); |
6021 LookupResult lookup(isolate()); | 5960 if (!info.CanLoadAsMonomorphic(types)) return false; |
6022 if (!CanLoadPropertyFromPrototype(map, name, &lookup)) return false; | 5961 if (!expr->ComputeTarget(info.map(), name)) return false; |
6023 | |
6024 Handle<Object> prototype(map->prototype(), isolate()); | |
6025 for (int count = 1; count < types->length(); ++count) { | |
6026 Handle<Map> test_map(types->at(count)); | |
6027 if (!CanLoadPropertyFromPrototype(test_map, name, &lookup)) return false; | |
6028 if (test_map->prototype() != *prototype) return false; | |
6029 } | |
6030 | |
6031 if (!expr->ComputeTarget(map, name)) return false; | |
6032 | 5962 |
6033 BuildCheckHeapObject(receiver); | 5963 BuildCheckHeapObject(receiver); |
6034 Add<HCheckMaps>(receiver, types); | 5964 Add<HCheckMaps>(receiver, types); |
6035 AddCheckPrototypeMaps(expr->holder(), map); | 5965 AddCheckPrototypeMaps(expr->holder(), info.map()); |
6036 if (FLAG_trace_inlining) { | 5966 if (FLAG_trace_inlining) { |
6037 Handle<JSFunction> caller = current_info()->closure(); | 5967 Handle<JSFunction> caller = current_info()->closure(); |
6038 SmartArrayPointer<char> caller_name = | 5968 SmartArrayPointer<char> caller_name = |
6039 caller->shared()->DebugName()->ToCString(); | 5969 caller->shared()->DebugName()->ToCString(); |
6040 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 5970 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
6041 *name->ToCString(), *caller_name); | 5971 *name->ToCString(), *caller_name); |
6042 } | 5972 } |
6043 | 5973 |
6044 if (!TryInlineCall(expr)) { | 5974 if (!TryInlineCall(expr)) { |
6045 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 5975 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
(...skipping 3651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9697 if (ShouldProduceTraceOutput()) { | 9627 if (ShouldProduceTraceOutput()) { |
9698 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9628 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
9699 } | 9629 } |
9700 | 9630 |
9701 #ifdef DEBUG | 9631 #ifdef DEBUG |
9702 graph_->Verify(false); // No full verify. | 9632 graph_->Verify(false); // No full verify. |
9703 #endif | 9633 #endif |
9704 } | 9634 } |
9705 | 9635 |
9706 } } // namespace v8::internal | 9636 } } // namespace v8::internal |
OLD | NEW |