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