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 6744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6755 | 6755 |
6756 | 6756 |
6757 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 6757 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
6758 Call* expr, | 6758 Call* expr, |
6759 HValue* receiver, | 6759 HValue* receiver, |
6760 SmallMapList* types, | 6760 SmallMapList* types, |
6761 Handle<String> name) { | 6761 Handle<String> name) { |
6762 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; | 6762 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; |
6763 | 6763 |
6764 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6764 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
6765 HBasicBlock* join = NULL; | |
6766 FunctionSorter order[kMaxCallPolymorphism]; | |
6767 int ordered_functions = 0; | |
6768 | 6765 |
6769 Handle<Map> initial_string_map( | 6766 Handle<Map> initial_string_map( |
6770 isolate()->native_context()->string_function()->initial_map()); | 6767 isolate()->native_context()->string_function()->initial_map()); |
6771 Handle<Map> string_marker_map( | 6768 Handle<Map> string_marker_map( |
6772 JSObject::cast(initial_string_map->prototype())->map()); | 6769 JSObject::cast(initial_string_map->prototype())->map()); |
6773 Handle<Map> initial_number_map( | 6770 Handle<Map> initial_number_map( |
6774 isolate()->native_context()->number_function()->initial_map()); | 6771 isolate()->native_context()->number_function()->initial_map()); |
6775 Handle<Map> number_marker_map( | 6772 Handle<Map> number_marker_map( |
6776 JSObject::cast(initial_number_map->prototype())->map()); | 6773 JSObject::cast(initial_number_map->prototype())->map()); |
6777 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | 6774 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
6778 | 6775 |
6779 bool handle_smi = false; | 6776 bool handle_smi = false; |
6780 | 6777 |
6778 // A map from functions to a set of receivers' maps. | |
6779 struct FuncMapEntry { | |
6780 Handle<JSFunction> func; | |
6781 SmallMapList maps; | |
6782 }; | |
6783 FuncMapEntry func_map[kMaxCallPolymorphism]; | |
6784 FunctionSorter order[kMaxCallPolymorphism]; | |
6785 int func_count = 0; | |
6786 int maps_count = 0; | |
6787 | |
6781 for (int i = 0; | 6788 for (int i = 0; |
6782 i < types->length() && ordered_functions < kMaxCallPolymorphism; | 6789 i < types->length() && func_count < kMaxCallPolymorphism; |
6783 ++i) { | 6790 ++i) { |
6784 Handle<Map> map = types->at(i); | 6791 Handle<Map> map = types->at(i); |
6785 if (expr->ComputeTarget(map, name)) { | 6792 if (expr->ComputeTarget(map, name)) { |
6786 if (map.is_identical_to(number_marker_map)) handle_smi = true; | 6793 if (map.is_identical_to(number_marker_map)) handle_smi = true; |
6787 order[ordered_functions++] = | 6794 |
6788 FunctionSorter(i, | 6795 // Try to find the target function among known targets. |
6789 expr->target()->shared()->profiler_ticks(), | 6796 int func_index = 0; |
6790 InliningAstSize(expr->target()), | 6797 for (; func_index < func_count; ++func_index) { |
6791 expr->target()->shared()->SourceSize()); | 6798 if (*func_map[func_index].func == *expr->target()) { |
6799 break; | |
6800 } | |
6801 } | |
6802 FuncMapEntry* entry = &func_map[func_index]; | |
6803 if (func_index == func_count) { | |
6804 // Entry not found, "allocate" it. | |
6805 entry->func = expr->target(); | |
6806 entry->maps.Reserve(types->length() - maps_count, zone()); | |
6807 order[func_index] = | |
6808 FunctionSorter(func_index, | |
6809 entry->func->shared()->profiler_ticks(), | |
6810 InliningAstSize(entry->func), | |
6811 entry->func->shared()->SourceSize()); | |
6812 ++func_count; | |
6813 } | |
6814 entry->maps.Add(map, zone()); | |
6815 ++maps_count; | |
6792 } | 6816 } |
6793 } | 6817 } |
6794 | 6818 |
6795 std::sort(order, order + ordered_functions); | 6819 std::sort(order, order + func_count); |
6796 | 6820 |
6797 HBasicBlock* number_block = NULL; | 6821 HBasicBlock* number_block = NULL; |
6822 HBasicBlock* join = NULL; | |
6798 | 6823 |
6799 for (int fn = 0; fn < ordered_functions; ++fn) { | 6824 if (func_count > 0) { |
6825 // Only needed once. | |
6826 join = graph()->CreateBasicBlock(); | |
6827 if (handle_smi) { | |
6828 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | |
6829 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | |
6830 number_block = graph()->CreateBasicBlock(); | |
6831 FinishCurrentBlock(New<HIsSmiAndBranch>( | |
6832 receiver, empty_smi_block, not_smi_block)); | |
Toon Verwaest
2014/01/03 07:42:49
4-space indent
| |
6833 Goto(empty_smi_block, number_block); | |
6834 set_current_block(not_smi_block); | |
6835 } else { | |
6836 BuildCheckHeapObject(receiver); | |
6837 } | |
6838 } | |
6839 | |
6840 for (int fn = 0; fn < func_count; ++fn) { | |
6800 int i = order[fn].index(); | 6841 int i = order[fn].index(); |
6801 Handle<Map> map = types->at(i); | 6842 FuncMapEntry* func_map_entry = &func_map[i]; |
6802 if (fn == 0) { | 6843 |
6803 // Only needed once. | 6844 HBasicBlock* call_block = graph()->CreateBasicBlock(); |
6804 join = graph()->CreateBasicBlock(); | 6845 HBasicBlock* if_false = NULL; |
6805 if (handle_smi) { | 6846 |
6806 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6847 int maps_count = func_map_entry->maps.length(); |
6807 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6848 for (int m = 0; m < maps_count; ++m) { |
6808 number_block = graph()->CreateBasicBlock(); | 6849 Handle<Map> map = func_map_entry->maps.at(m); |
6809 FinishCurrentBlock(New<HIsSmiAndBranch>( | 6850 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
6810 receiver, empty_smi_block, not_smi_block)); | 6851 if_false = graph()->CreateBasicBlock(); |
6811 Goto(empty_smi_block, number_block); | 6852 HUnaryControlInstruction* compare; |
6812 set_current_block(not_smi_block); | 6853 |
6854 if (handle_smi && map.is_identical_to(number_marker_map)) { | |
6855 compare = | |
6856 New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | |
6857 map = initial_number_map; | |
6858 expr->set_number_check( | |
6859 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
6860 } else if (map.is_identical_to(string_marker_map)) { | |
6861 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | |
6862 map = initial_string_map; | |
6863 expr->set_string_check( | |
6864 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
6813 } else { | 6865 } else { |
6814 BuildCheckHeapObject(receiver); | 6866 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
6867 expr->set_map_check(); | |
6815 } | 6868 } |
6816 } | |
6817 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
6818 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
6819 HUnaryControlInstruction* compare; | |
6820 | 6869 |
6821 if (handle_smi && map.is_identical_to(number_marker_map)) { | 6870 FinishCurrentBlock(compare); |
6822 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | 6871 |
6823 map = initial_number_map; | 6872 if (expr->check_type() == NUMBER_CHECK) { |
6824 expr->set_number_check( | 6873 Goto(if_true, number_block); |
6825 Handle<JSObject>(JSObject::cast(map->prototype()))); | 6874 if_true = number_block; |
6826 } else if (map.is_identical_to(string_marker_map)) { | 6875 number_block->SetJoinId(expr->id()); |
6827 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | 6876 } |
6828 map = initial_string_map; | 6877 set_current_block(if_true); |
6829 expr->set_string_check( | 6878 |
6830 Handle<JSObject>(JSObject::cast(map->prototype()))); | 6879 expr->ComputeTarget(map, name); |
6831 } else { | 6880 ASSERT(*expr->target() == *func_map_entry->func); |
6832 compare = New<HCompareMap>(receiver, map, if_true, if_false); | 6881 |
6833 expr->set_map_check(); | 6882 AddCheckPrototypeMaps(expr->holder(), map); |
6883 | |
6884 Goto(if_true, call_block); | |
6885 | |
6886 set_current_block(if_false); | |
6834 } | 6887 } |
6835 | 6888 |
6836 FinishCurrentBlock(compare); | 6889 // Generate call once for all corresponding maps. |
6890 call_block->SetJoinId(expr->id()); | |
6891 set_current_block(call_block); | |
6837 | 6892 |
6838 if (expr->check_type() == NUMBER_CHECK) { | |
6839 Goto(if_true, number_block); | |
6840 if_true = number_block; | |
6841 number_block->SetJoinId(expr->id()); | |
6842 } | |
6843 set_current_block(if_true); | |
6844 | |
6845 expr->ComputeTarget(map, name); | |
6846 AddCheckPrototypeMaps(expr->holder(), map); | |
6847 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 6893 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
6848 Handle<JSFunction> caller = current_info()->closure(); | 6894 Handle<JSFunction> caller = current_info()->closure(); |
6849 SmartArrayPointer<char> caller_name = | 6895 SmartArrayPointer<char> caller_name = |
6850 caller->shared()->DebugName()->ToCString(); | 6896 caller->shared()->DebugName()->ToCString(); |
6851 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6897 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
6852 name->ToCString().get(), | 6898 name->ToCString().get(), |
6853 caller_name.get()); | 6899 caller_name.get()); |
6854 } | 6900 } |
6855 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 6901 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
6856 // Trying to inline will signal that we should bailout from the | 6902 // Trying to inline will signal that we should bailout from the |
6857 // entire compilation by setting stack overflow on the visitor. | 6903 // entire compilation by setting stack overflow on the visitor. |
6858 if (HasStackOverflow()) return; | 6904 if (HasStackOverflow()) return; |
6859 } else { | 6905 } else { |
6860 HCallConstantFunction* call = | 6906 HCallConstantFunction* call = |
6861 New<HCallConstantFunction>(expr->target(), argument_count); | 6907 New<HCallConstantFunction>(expr->target(), argument_count); |
6862 PreProcessCall(call); | 6908 PreProcessCall(call); |
6863 AddInstruction(call); | 6909 AddInstruction(call); |
6864 if (!ast_context()->IsEffect()) Push(call); | 6910 if (!ast_context()->IsEffect()) Push(call); |
6865 } | 6911 } |
6912 if (current_block() != NULL) Goto(join); | |
6866 | 6913 |
6867 if (current_block() != NULL) Goto(join); | |
6868 set_current_block(if_false); | 6914 set_current_block(if_false); |
6869 } | 6915 } |
6870 | 6916 |
6871 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 6917 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
6872 // know about and do not want to handle ones we've never seen. Otherwise | 6918 // know about and do not want to handle ones we've never seen. Otherwise |
6873 // use a generic IC. | 6919 // use a generic IC. |
6874 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 6920 if (maps_count == types->length() && FLAG_deoptimize_uncommon_cases) { |
6875 // Because the deopt may be the only path in the polymorphic call, make sure | 6921 // Because the deopt may be the only path in the polymorphic call, make sure |
6876 // that the environment stack matches the depth on deopt that it otherwise | 6922 // that the environment stack matches the depth on deopt that it otherwise |
6877 // would have had after a successful call. | 6923 // would have had after a successful call. |
6878 Drop(argument_count); | 6924 Drop(argument_count); |
6879 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 6925 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
6880 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); | 6926 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
6881 } else { | 6927 } else { |
6882 HCallNamed* call = New<HCallNamed>(name, argument_count); | 6928 HCallNamed* call = New<HCallNamed>(name, argument_count); |
6883 PreProcessCall(call); | 6929 PreProcessCall(call); |
6884 | 6930 |
(...skipping 3907 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10792 if (ShouldProduceTraceOutput()) { | 10838 if (ShouldProduceTraceOutput()) { |
10793 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10839 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10794 } | 10840 } |
10795 | 10841 |
10796 #ifdef DEBUG | 10842 #ifdef DEBUG |
10797 graph_->Verify(false); // No full verify. | 10843 graph_->Verify(false); // No full verify. |
10798 #endif | 10844 #endif |
10799 } | 10845 } |
10800 | 10846 |
10801 } } // namespace v8::internal | 10847 } } // namespace v8::internal |
OLD | NEW |