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 4595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4606 | 4606 |
4607 Handle<JSObject> holder(lookup.holder()); | 4607 Handle<JSObject> holder(lookup.holder()); |
4608 Handle<Map> holder_map(holder->map()); | 4608 Handle<Map> holder_map(holder->map()); |
4609 BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype), holder); | 4609 BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype), holder); |
4610 HValue* holder_value = Add<HConstant>(holder); | 4610 HValue* holder_value = Add<HConstant>(holder); |
4611 return BuildLoadNamedField(holder_value, | 4611 return BuildLoadNamedField(holder_value, |
4612 HObjectAccess::ForField(holder_map, &lookup, name)); | 4612 HObjectAccess::ForField(holder_map, &lookup, name)); |
4613 } | 4613 } |
4614 | 4614 |
4615 | 4615 |
| 4616 // Returns true if an instance of this map can never find a property with this |
| 4617 // name in its prototype chain. This means all prototypes up to the top are |
| 4618 // fast and don't have the name in them. It would be good if we could optimize |
| 4619 // polymorphic loads where the property is sometimes found in the prototype |
| 4620 // chain. |
| 4621 static bool PrototypeChainCanNeverResolve( |
| 4622 Handle<Map> map, Handle<String> name) { |
| 4623 Isolate* isolate = map->GetIsolate(); |
| 4624 Object* current = map->prototype(); |
| 4625 while (current != isolate->heap()->null_value()) { |
| 4626 if (current->IsJSGlobalProxy() || |
| 4627 current->IsGlobalObject() || |
| 4628 !current->IsJSObject() || |
| 4629 JSObject::cast(current)->map()->has_named_interceptor() || |
| 4630 JSObject::cast(current)->IsAccessCheckNeeded() || |
| 4631 !JSObject::cast(current)->HasFastProperties()) { |
| 4632 return false; |
| 4633 } |
| 4634 |
| 4635 LookupResult lookup(isolate); |
| 4636 Map* map = JSObject::cast(current)->map(); |
| 4637 map->LookupDescriptor(NULL, *name, &lookup); |
| 4638 if (lookup.IsFound()) return false; |
| 4639 if (!lookup.IsCacheable()) return false; |
| 4640 current = JSObject::cast(current)->GetPrototype(); |
| 4641 } |
| 4642 return true; |
| 4643 } |
| 4644 |
| 4645 |
4616 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 4646 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
4617 Property* expr, | 4647 Property* expr, |
4618 HValue* object, | 4648 HValue* object, |
4619 SmallMapList* types, | 4649 SmallMapList* types, |
4620 Handle<String> name) { | 4650 Handle<String> name) { |
4621 HInstruction* instr = TryLoadPolymorphicAsMonomorphic( | 4651 HInstruction* instr = TryLoadPolymorphicAsMonomorphic( |
4622 expr, object, types, name); | 4652 expr, object, types, name); |
4623 if (instr == NULL) { | 4653 if (instr != NULL) { |
4624 // Something did not match; must use a polymorphic load. | 4654 instr->set_position(expr->position()); |
4625 BuildCheckHeapObject(object); | 4655 return ast_context()->ReturnInstruction(instr, expr->id()); |
4626 HValue* context = environment()->context(); | |
4627 instr = new(zone()) HLoadNamedFieldPolymorphic( | |
4628 context, object, types, name, zone()); | |
4629 } | 4656 } |
4630 | 4657 |
4631 instr->set_position(expr->position()); | 4658 // Something did not match; must use a polymorphic load. |
4632 return ast_context()->ReturnInstruction(instr, expr->id()); | 4659 int count = 0; |
| 4660 HBasicBlock* join = NULL; |
| 4661 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 4662 Handle<Map> map = types->at(i); |
| 4663 LookupResult lookup(isolate()); |
| 4664 if (ComputeLoadStoreField(map, name, &lookup, false) || |
| 4665 (lookup.IsCacheable() && |
| 4666 !map->is_dictionary_map() && |
| 4667 !map->has_named_interceptor() && |
| 4668 (lookup.IsConstant() || |
| 4669 (!lookup.IsFound() && |
| 4670 PrototypeChainCanNeverResolve(map, name))))) { |
| 4671 if (count == 0) { |
| 4672 BuildCheckHeapObject(object); |
| 4673 join = graph()->CreateBasicBlock(); |
| 4674 } |
| 4675 ++count; |
| 4676 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 4677 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 4678 HCompareMap* compare = |
| 4679 new(zone()) HCompareMap(object, map, if_true, if_false); |
| 4680 current_block()->Finish(compare); |
| 4681 |
| 4682 set_current_block(if_true); |
| 4683 |
| 4684 // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. |
| 4685 if (lookup.IsField()) { |
| 4686 HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); |
| 4687 HLoadNamedField* load = BuildLoadNamedField(object, access); |
| 4688 load->set_position(expr->position()); |
| 4689 AddInstruction(load); |
| 4690 if (!ast_context()->IsEffect()) Push(load); |
| 4691 } else if (lookup.IsConstant()) { |
| 4692 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); |
| 4693 HConstant* hconstant = Add<HConstant>(constant); |
| 4694 if (!ast_context()->IsEffect()) Push(hconstant); |
| 4695 } else { |
| 4696 ASSERT(!lookup.IsFound()); |
| 4697 if (map->prototype()->IsJSObject()) { |
| 4698 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
| 4699 Handle<JSObject> holder = prototype; |
| 4700 while (holder->map()->prototype()->IsJSObject()) { |
| 4701 holder = handle(JSObject::cast(holder->map()->prototype())); |
| 4702 } |
| 4703 BuildCheckPrototypeMaps(prototype, holder); |
| 4704 } |
| 4705 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); |
| 4706 } |
| 4707 |
| 4708 current_block()->Goto(join); |
| 4709 set_current_block(if_false); |
| 4710 } |
| 4711 } |
| 4712 |
| 4713 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 4714 // know about and do not want to handle ones we've never seen. Otherwise |
| 4715 // use a generic IC. |
| 4716 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 4717 FinishExitWithHardDeoptimization(join); |
| 4718 } else { |
| 4719 HInstruction* load = BuildLoadNamedGeneric(object, name, expr); |
| 4720 load->set_position(expr->position()); |
| 4721 AddInstruction(load); |
| 4722 if (!ast_context()->IsEffect()) Push(load); |
| 4723 |
| 4724 if (join != NULL) { |
| 4725 current_block()->Goto(join); |
| 4726 } else { |
| 4727 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 4728 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 4729 return; |
| 4730 } |
| 4731 } |
| 4732 |
| 4733 ASSERT(join != NULL); |
| 4734 join->SetJoinId(expr->id()); |
| 4735 set_current_block(join); |
| 4736 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
4633 } | 4737 } |
4634 | 4738 |
4635 | 4739 |
4636 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( | 4740 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( |
4637 int position, | 4741 int position, |
4638 BailoutId assignment_id, | 4742 BailoutId assignment_id, |
4639 HValue* object, | 4743 HValue* object, |
4640 HValue* store_value, | 4744 HValue* store_value, |
4641 HValue* result_value, | 4745 HValue* result_value, |
4642 SmallMapList* types, | 4746 SmallMapList* types, |
(...skipping 5086 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9729 if (ShouldProduceTraceOutput()) { | 9833 if (ShouldProduceTraceOutput()) { |
9730 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9834 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
9731 } | 9835 } |
9732 | 9836 |
9733 #ifdef DEBUG | 9837 #ifdef DEBUG |
9734 graph_->Verify(false); // No full verify. | 9838 graph_->Verify(false); // No full verify. |
9735 #endif | 9839 #endif |
9736 } | 9840 } |
9737 | 9841 |
9738 } } // namespace v8::internal | 9842 } } // namespace v8::internal |
OLD | NEW |