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 5592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5603 if (info->lookup()->IsConstant()) { | 5603 if (info->lookup()->IsConstant()) { |
5604 // Check whether we are trying to store the same constant. | 5604 // Check whether we are trying to store the same constant. |
5605 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); | 5605 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); |
5606 } | 5606 } |
5607 | 5607 |
5608 ASSERT(info->lookup()->IsField() || info->lookup()->IsTransition()); | 5608 ASSERT(info->lookup()->IsField() || info->lookup()->IsTransition()); |
5609 return BuildStoreNamedField(info, checked_object, value); | 5609 return BuildStoreNamedField(info, checked_object, value); |
5610 } | 5610 } |
5611 | 5611 |
5612 | 5612 |
5613 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 5613 void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( |
| 5614 PropertyAccessType access_type, |
5614 BailoutId ast_id, | 5615 BailoutId ast_id, |
5615 BailoutId return_id, | 5616 BailoutId return_id, |
5616 HValue* object, | 5617 HValue* object, |
| 5618 HValue* value, |
5617 SmallMapList* types, | 5619 SmallMapList* types, |
5618 Handle<String> name) { | 5620 Handle<String> name) { |
5619 // Something did not match; must use a polymorphic load. | 5621 // Something did not match; must use a polymorphic load. |
5620 int count = 0; | 5622 int count = 0; |
5621 HBasicBlock* join = NULL; | 5623 HBasicBlock* join = NULL; |
5622 HBasicBlock* number_block = NULL; | 5624 HBasicBlock* number_block = NULL; |
5623 bool handled_string = false; | 5625 bool handled_string = false; |
5624 | 5626 |
5625 bool handle_smi = false; | 5627 bool handle_smi = false; |
| 5628 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); |
5626 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5629 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
5627 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); | 5630 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); |
5628 if (info.type()->Is(Type::String())) { | 5631 if (info.type()->Is(Type::String())) { |
5629 if (handled_string) continue; | 5632 if (handled_string) continue; |
5630 handled_string = true; | 5633 handled_string = true; |
5631 } | 5634 } |
5632 if (info.CanAccessMonomorphic()) { | 5635 if (info.CanAccessMonomorphic()) { |
5633 count++; | 5636 count++; |
5634 if (info.type()->Is(Type::Number())) { | 5637 if (info.type()->Is(Type::Number())) { |
5635 handle_smi = true; | 5638 handle_smi = true; |
5636 break; | 5639 break; |
5637 } | 5640 } |
5638 } | 5641 } |
5639 } | 5642 } |
5640 | 5643 |
5641 count = 0; | 5644 count = 0; |
5642 HControlInstruction* smi_check = NULL; | 5645 HControlInstruction* smi_check = NULL; |
5643 handled_string = false; | 5646 handled_string = false; |
5644 | 5647 |
5645 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5648 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
5646 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); | 5649 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); |
5647 if (info.type()->Is(Type::String())) { | 5650 if (info.type()->Is(Type::String())) { |
5648 if (handled_string) continue; | 5651 if (handled_string) continue; |
5649 handled_string = true; | 5652 handled_string = true; |
5650 } | 5653 } |
5651 if (!info.CanAccessMonomorphic()) continue; | 5654 if (!info.CanAccessMonomorphic()) continue; |
5652 | 5655 |
5653 if (count == 0) { | 5656 if (count == 0) { |
5654 join = graph()->CreateBasicBlock(); | 5657 join = graph()->CreateBasicBlock(); |
5655 if (handle_smi) { | 5658 if (handle_smi) { |
5656 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 5659 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
(...skipping 28 matching lines...) Expand all Loading... |
5685 FinishCurrentBlock(compare); | 5688 FinishCurrentBlock(compare); |
5686 | 5689 |
5687 if (info.type()->Is(Type::Number())) { | 5690 if (info.type()->Is(Type::Number())) { |
5688 Goto(if_true, number_block); | 5691 Goto(if_true, number_block); |
5689 if_true = number_block; | 5692 if_true = number_block; |
5690 number_block->SetJoinId(ast_id); | 5693 number_block->SetJoinId(ast_id); |
5691 } | 5694 } |
5692 | 5695 |
5693 set_current_block(if_true); | 5696 set_current_block(if_true); |
5694 | 5697 |
5695 HInstruction* load = BuildLoadMonomorphic( | 5698 HInstruction* access = NULL; |
5696 &info, object, dependency, ast_id, | 5699 HValue* result = NULL; |
5697 return_id, FLAG_polymorphic_inlining); | 5700 switch (access_type) { |
5698 if (load == NULL) { | 5701 case LOAD: |
| 5702 access = BuildLoadMonomorphic( |
| 5703 &info, object, dependency, ast_id, |
| 5704 return_id, FLAG_polymorphic_inlining); |
| 5705 result = access; |
| 5706 break; |
| 5707 case STORE: |
| 5708 access = BuildStoreMonomorphic( |
| 5709 &info, dependency, value, ast_id, return_id, |
| 5710 FLAG_polymorphic_inlining); |
| 5711 result = value; |
| 5712 break; |
| 5713 } |
| 5714 |
| 5715 if (access == NULL) { |
5699 if (HasStackOverflow()) return; | 5716 if (HasStackOverflow()) return; |
5700 } else { | 5717 } else { |
5701 if (!load->IsLinked()) { | 5718 if (!access->IsLinked()) AddInstruction(access); |
5702 AddInstruction(load); | 5719 if (!ast_context()->IsEffect()) Push(result); |
5703 } | |
5704 if (!ast_context()->IsEffect()) Push(load); | |
5705 } | 5720 } |
5706 | 5721 |
5707 if (current_block() != NULL) Goto(join); | 5722 if (current_block() != NULL) Goto(join); |
5708 set_current_block(if_false); | 5723 set_current_block(if_false); |
5709 } | 5724 } |
5710 | 5725 |
5711 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5726 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
5712 // know about and do not want to handle ones we've never seen. Otherwise | 5727 // know about and do not want to handle ones we've never seen. Otherwise |
5713 // use a generic IC. | 5728 // use a generic IC. |
5714 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5729 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
5715 // Because the deopt may be the only path in the polymorphic load, make sure | 5730 // Because the deopt may be the only path in the polymorphic load, make sure |
5716 // that the environment stack matches the depth on deopt that it otherwise | 5731 // that the environment stack matches the depth on deopt that it otherwise |
5717 // would have had after a successful load. | 5732 // would have had after a successful load. |
5718 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 5733 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
5719 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | 5734 const char* message = ""; |
| 5735 switch (access_type) { |
| 5736 case LOAD: |
| 5737 message = "Unknown map in polymorphic load"; |
| 5738 break; |
| 5739 case STORE: |
| 5740 message = "Unknown map in polymorphic store"; |
| 5741 break; |
| 5742 } |
| 5743 FinishExitWithHardDeoptimization(message, join); |
5720 } else { | 5744 } else { |
5721 HInstruction* load = Add<HLoadNamedGeneric>(object, name); | 5745 HValue* result = NULL; |
5722 if (!ast_context()->IsEffect()) Push(load); | 5746 switch (access_type) { |
| 5747 case LOAD: |
| 5748 result = Add<HLoadNamedGeneric>(object, name); |
| 5749 break; |
| 5750 case STORE: |
| 5751 AddInstruction(BuildStoreNamedGeneric(object, name, value)); |
| 5752 result = value; |
| 5753 break; |
| 5754 } |
| 5755 if (!ast_context()->IsEffect()) Push(result); |
5723 | 5756 |
5724 if (join != NULL) { | 5757 if (join != NULL) { |
5725 Goto(join); | 5758 Goto(join); |
5726 } else { | 5759 } else { |
5727 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5760 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
5728 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 5761 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
5729 return; | 5762 return; |
5730 } | 5763 } |
5731 } | 5764 } |
5732 | 5765 |
5733 ASSERT(join != NULL); | 5766 ASSERT(join != NULL); |
5734 join->SetJoinId(ast_id); | 5767 join->SetJoinId(ast_id); |
5735 set_current_block(join); | 5768 set_current_block(join); |
5736 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 5769 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
5737 } | 5770 } |
5738 | 5771 |
5739 | 5772 |
5740 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( | |
5741 BailoutId assignment_id, | |
5742 BailoutId return_id, | |
5743 HValue* object, | |
5744 HValue* value, | |
5745 SmallMapList* types, | |
5746 Handle<String> name) { | |
5747 int count = 0; | |
5748 HBasicBlock* join = NULL; | |
5749 // TODO(verwaest): Unify with polymorphic load handling. | |
5750 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | |
5751 PropertyAccessInfo info(this, STORE, ToType(types->at(i)), name); | |
5752 if (info.CanAccessMonomorphic()) { | |
5753 if (count == 0) { | |
5754 BuildCheckHeapObject(object); | |
5755 join = graph()->CreateBasicBlock(); | |
5756 } | |
5757 ++count; | |
5758 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
5759 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
5760 HCompareMap* compare = New<HCompareMap>( | |
5761 object, info.map(), if_true, if_false); | |
5762 FinishCurrentBlock(compare); | |
5763 | |
5764 set_current_block(if_true); | |
5765 | |
5766 HInstruction* store; | |
5767 store = BuildStoreMonomorphic( | |
5768 &info, compare, value, assignment_id, return_id, | |
5769 FLAG_polymorphic_inlining); | |
5770 | |
5771 if (store == NULL) { | |
5772 if (HasStackOverflow()) return; | |
5773 } else { | |
5774 ASSERT(!store->IsLinked()); | |
5775 AddInstruction(store); | |
5776 if (!ast_context()->IsEffect()) Push(value); | |
5777 } | |
5778 | |
5779 if (current_block() != NULL) Goto(join); | |
5780 set_current_block(if_false); | |
5781 } | |
5782 } | |
5783 | |
5784 // Finish up. Unconditionally deoptimize if we've handled all the maps we | |
5785 // know about and do not want to handle ones we've never seen. Otherwise | |
5786 // use a generic IC. | |
5787 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | |
5788 FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); | |
5789 } else { | |
5790 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | |
5791 AddInstruction(instr); | |
5792 | |
5793 if (join != NULL) { | |
5794 if (!ast_context()->IsEffect()) { | |
5795 Push(value); | |
5796 } | |
5797 Goto(join); | |
5798 } else { | |
5799 // The HSimulate for the store should not see the stored value in | |
5800 // effect contexts (it is not materialized at expr->id() in the | |
5801 // unoptimized code). | |
5802 if (instr->HasObservableSideEffects()) { | |
5803 if (ast_context()->IsEffect()) { | |
5804 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); | |
5805 } else { | |
5806 Push(value); | |
5807 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); | |
5808 Drop(1); | |
5809 } | |
5810 } | |
5811 return ast_context()->ReturnValue(value); | |
5812 } | |
5813 } | |
5814 | |
5815 ASSERT(join != NULL); | |
5816 join->SetJoinId(assignment_id); | |
5817 set_current_block(join); | |
5818 if (!ast_context()->IsEffect()) { | |
5819 ast_context()->ReturnValue(Pop()); | |
5820 } | |
5821 } | |
5822 | |
5823 | |
5824 static bool ComputeReceiverTypes(Expression* expr, | 5773 static bool ComputeReceiverTypes(Expression* expr, |
5825 HValue* receiver, | 5774 HValue* receiver, |
5826 SmallMapList** t, | 5775 SmallMapList** t, |
5827 Zone* zone) { | 5776 Zone* zone) { |
5828 SmallMapList* types = expr->GetReceiverTypes(); | 5777 SmallMapList* types = expr->GetReceiverTypes(); |
5829 *t = types; | 5778 *t = types; |
5830 bool monomorphic = expr->IsMonomorphic(); | 5779 bool monomorphic = expr->IsMonomorphic(); |
5831 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { | 5780 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { |
5832 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); | 5781 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); |
5833 types->FilterForPossibleTransitions(root_map); | 5782 types->FilterForPossibleTransitions(root_map); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5875 ASSERT(!name.is_null()); | 5824 ASSERT(!name.is_null()); |
5876 | 5825 |
5877 HInstruction* instr = NULL; | 5826 HInstruction* instr = NULL; |
5878 | 5827 |
5879 SmallMapList* types; | 5828 SmallMapList* types; |
5880 ComputeReceiverTypes(expr, object, &types, zone()); | 5829 ComputeReceiverTypes(expr, object, &types, zone()); |
5881 | 5830 |
5882 if (types->length() > 0) { | 5831 if (types->length() > 0) { |
5883 PropertyAccessInfo info(this, STORE, ToType(types->first()), name); | 5832 PropertyAccessInfo info(this, STORE, ToType(types->first()), name); |
5884 if (!info.CanAccessAsMonomorphic(types)) { | 5833 if (!info.CanAccessAsMonomorphic(types)) { |
5885 return HandlePolymorphicStoreNamedField( | 5834 return HandlePolymorphicNamedFieldAccess( |
5886 ast_id, return_id, object, value, types, name); | 5835 STORE, ast_id, return_id, object, value, types, name); |
5887 } | 5836 } |
5888 | 5837 |
5889 ASSERT(!info.type()->Is(Type::Number())); | 5838 ASSERT(!info.type()->Is(Type::Number())); |
5890 BuildCheckHeapObject(object); | 5839 BuildCheckHeapObject(object); |
5891 HValue* checked_object; | 5840 HValue* checked_object; |
5892 if (AreStringTypes(types)) { | 5841 if (AreStringTypes(types)) { |
5893 checked_object = Add<HCheckInstanceType>( | 5842 checked_object = Add<HCheckInstanceType>( |
5894 object, HCheckInstanceType::IS_STRING); | 5843 object, HCheckInstanceType::IS_STRING); |
5895 } else { | 5844 } else { |
5896 checked_object = Add<HCheckMaps>(object, types); | 5845 checked_object = Add<HCheckMaps>(object, types); |
(...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6727 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 6676 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
6728 HValue* object = Pop(); | 6677 HValue* object = Pop(); |
6729 | 6678 |
6730 SmallMapList* types; | 6679 SmallMapList* types; |
6731 ComputeReceiverTypes(expr, object, &types, zone()); | 6680 ComputeReceiverTypes(expr, object, &types, zone()); |
6732 ASSERT(types != NULL); | 6681 ASSERT(types != NULL); |
6733 | 6682 |
6734 if (types->length() > 0) { | 6683 if (types->length() > 0) { |
6735 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name); | 6684 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name); |
6736 if (!info.CanAccessAsMonomorphic(types)) { | 6685 if (!info.CanAccessAsMonomorphic(types)) { |
6737 return HandlePolymorphicLoadNamedField( | 6686 return HandlePolymorphicNamedFieldAccess( |
6738 ast_id, expr->LoadId(), object, types, name); | 6687 LOAD, ast_id, expr->LoadId(), object, NULL, types, name); |
6739 } | 6688 } |
6740 | 6689 |
6741 HValue* checked_object; | 6690 HValue* checked_object; |
6742 // Type::Number() is only supported by polymorphic load/call handling. | 6691 // Type::Number() is only supported by polymorphic load/call handling. |
6743 ASSERT(!info.type()->Is(Type::Number())); | 6692 ASSERT(!info.type()->Is(Type::Number())); |
6744 BuildCheckHeapObject(object); | 6693 BuildCheckHeapObject(object); |
6745 if (AreStringTypes(types)) { | 6694 if (AreStringTypes(types)) { |
6746 checked_object = | 6695 checked_object = |
6747 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); | 6696 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); |
6748 } else { | 6697 } else { |
(...skipping 4473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11222 if (ShouldProduceTraceOutput()) { | 11171 if (ShouldProduceTraceOutput()) { |
11223 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11172 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11224 } | 11173 } |
11225 | 11174 |
11226 #ifdef DEBUG | 11175 #ifdef DEBUG |
11227 graph_->Verify(false); // No full verify. | 11176 graph_->Verify(false); // No full verify. |
11228 #endif | 11177 #endif |
11229 } | 11178 } |
11230 | 11179 |
11231 } } // namespace v8::internal | 11180 } } // namespace v8::internal |
OLD | NEW |