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 NoObservableSideEffectsScope no_side_effects(this); |
ulan
2013/08/06 13:36:24
Shouldn't this be in its own scope (i.e. surrounde
| |
4632 return ast_context()->ReturnInstruction(instr, expr->id()); | 4659 // Something did not match; must use a polymorphic load. |
4660 int count = 0; | |
4661 HBasicBlock* join = NULL; | |
4662 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | |
4663 Handle<Map> map = types->at(i); | |
4664 LookupResult lookup(isolate()); | |
4665 if (ComputeLoadStoreField(map, name, &lookup, false) || | |
4666 (lookup.IsCacheable() && | |
4667 !map->is_dictionary_map() && | |
4668 !map->has_named_interceptor() && | |
4669 (lookup.IsConstant() || | |
4670 (!lookup.IsFound() && | |
4671 PrototypeChainCanNeverResolve(map, name))))) { | |
4672 if (count == 0) { | |
4673 BuildCheckHeapObject(object); | |
4674 join = graph()->CreateBasicBlock(); | |
4675 } | |
4676 ++count; | |
4677 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
4678 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
4679 HCompareMap* compare = | |
4680 new(zone()) HCompareMap(object, map, if_true, if_false); | |
4681 current_block()->Finish(compare); | |
4682 | |
4683 set_current_block(if_true); | |
4684 | |
4685 // TODO(verwaest): Merge logic with BuildLoadNamedMonomorphic. | |
4686 if (lookup.IsField()) { | |
4687 HObjectAccess access = HObjectAccess::ForField(map, &lookup, name); | |
4688 HLoadNamedField* load = BuildLoadNamedField(object, access); | |
4689 load->set_position(expr->position()); | |
4690 AddInstruction(load); | |
4691 Push(load); | |
4692 } else if (lookup.IsConstant()) { | |
4693 Handle<Object> constant(lookup.GetConstantFromMap(*map), isolate()); | |
4694 HConstant* hconstant = Add<HConstant>(constant); | |
4695 Push(hconstant); | |
4696 } else { | |
4697 ASSERT(!lookup.IsFound()); | |
4698 if (map->prototype()->IsJSObject()) { | |
4699 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | |
4700 Handle<JSObject> holder = prototype; | |
4701 while (holder->map()->prototype()->IsJSObject()) { | |
4702 holder = handle(JSObject::cast(holder->map()->prototype())); | |
4703 } | |
4704 BuildCheckPrototypeMaps(prototype, holder); | |
4705 } | |
4706 Push(graph()->GetConstantUndefined()); | |
4707 } | |
4708 | |
4709 current_block()->Goto(join, NULL, false); | |
4710 set_current_block(if_false); | |
4711 } | |
4712 } | |
4713 | |
4714 // Finish up. Unconditionally deoptimize if we've handled all the maps we | |
4715 // know about and do not want to handle ones we've never seen. Otherwise | |
4716 // use a generic IC. | |
4717 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | |
4718 FinishExitWithHardDeoptimization(join); | |
4719 } else { | |
4720 HInstruction* load = BuildLoadNamedGeneric(object, name, expr); | |
ulan
2013/08/06 13:36:24
Why it is in NoObservableSideEffectsScope scope?
Toon Verwaest
2013/08/06 14:03:44
Scary premature optimization attempt. Removed :)
| |
4721 load->set_position(expr->position()); | |
4722 AddInstruction(load); | |
4723 Push(load); | |
4724 | |
4725 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | |
4726 | |
4727 if (join != NULL) { | |
4728 current_block()->Goto(join, NULL, false); | |
4729 } else { | |
4730 return ast_context()->ReturnValue(Pop()); | |
4731 } | |
4732 } | |
4733 | |
4734 ASSERT(join != NULL); | |
4735 set_current_block(join); | |
4736 return 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 |