Chromium Code Reviews| 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 |