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