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 6837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6848 | 6848 |
6849 | 6849 |
6850 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 6850 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
6851 Call* expr, | 6851 Call* expr, |
6852 HValue* receiver, | 6852 HValue* receiver, |
6853 SmallMapList* types, | 6853 SmallMapList* types, |
6854 Handle<String> name) { | 6854 Handle<String> name) { |
6855 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; | 6855 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; |
6856 | 6856 |
6857 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6857 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 6858 HBasicBlock* join = NULL; |
| 6859 FunctionSorter order[kMaxCallPolymorphism]; |
| 6860 int ordered_functions = 0; |
6858 | 6861 |
6859 Handle<Map> initial_string_map( | 6862 Handle<Map> initial_string_map( |
6860 isolate()->native_context()->string_function()->initial_map()); | 6863 isolate()->native_context()->string_function()->initial_map()); |
6861 Handle<Map> string_marker_map( | 6864 Handle<Map> string_marker_map( |
6862 JSObject::cast(initial_string_map->prototype())->map()); | 6865 JSObject::cast(initial_string_map->prototype())->map()); |
6863 Handle<Map> initial_number_map( | 6866 Handle<Map> initial_number_map( |
6864 isolate()->native_context()->number_function()->initial_map()); | 6867 isolate()->native_context()->number_function()->initial_map()); |
6865 Handle<Map> number_marker_map( | 6868 Handle<Map> number_marker_map( |
6866 JSObject::cast(initial_number_map->prototype())->map()); | 6869 JSObject::cast(initial_number_map->prototype())->map()); |
6867 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | 6870 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
6868 | 6871 |
6869 bool handle_smi = false; | 6872 bool handle_smi = false; |
6870 | 6873 |
6871 // A map from functions to a set of receivers' maps. | |
6872 struct FuncMapEntry { | |
6873 Handle<JSFunction> func; | |
6874 SmallMapList maps; | |
6875 }; | |
6876 FuncMapEntry func_map[kMaxCallPolymorphism]; | |
6877 FunctionSorter order[kMaxCallPolymorphism]; | |
6878 int func_count = 0; | |
6879 int maps_count = 0; | |
6880 | |
6881 for (int i = 0; | 6874 for (int i = 0; |
6882 i < types->length() && func_count < kMaxCallPolymorphism; | 6875 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
6883 ++i) { | 6876 ++i) { |
6884 Handle<Map> map = types->at(i); | 6877 Handle<Map> map = types->at(i); |
6885 if (expr->ComputeTarget(map, name)) { | 6878 if (expr->ComputeTarget(map, name)) { |
6886 if (map.is_identical_to(number_marker_map)) handle_smi = true; | 6879 if (map.is_identical_to(number_marker_map)) handle_smi = true; |
6887 | 6880 order[ordered_functions++] = |
6888 // Try to find the target function among known targets. | 6881 FunctionSorter(i, |
6889 int func_index = 0; | 6882 expr->target()->shared()->profiler_ticks(), |
6890 for (; func_index < func_count; ++func_index) { | 6883 InliningAstSize(expr->target()), |
6891 if (*func_map[func_index].func == *expr->target()) { | 6884 expr->target()->shared()->SourceSize()); |
6892 break; | |
6893 } | |
6894 } | |
6895 FuncMapEntry* entry = &func_map[func_index]; | |
6896 if (func_index == func_count) { | |
6897 // Entry not found, "allocate" it. | |
6898 entry->func = expr->target(); | |
6899 entry->maps.Reserve(types->length() - maps_count, zone()); | |
6900 order[func_index] = | |
6901 FunctionSorter(func_index, | |
6902 entry->func->shared()->profiler_ticks(), | |
6903 InliningAstSize(entry->func), | |
6904 entry->func->shared()->SourceSize()); | |
6905 ++func_count; | |
6906 } | |
6907 entry->maps.Add(map, zone()); | |
6908 ++maps_count; | |
6909 } | 6885 } |
6910 } | 6886 } |
6911 | 6887 |
6912 std::sort(order, order + func_count); | 6888 std::sort(order, order + ordered_functions); |
6913 | 6889 |
6914 HBasicBlock* number_block = NULL; | 6890 HBasicBlock* number_block = NULL; |
6915 HBasicBlock* join = NULL; | |
6916 | 6891 |
6917 if (func_count > 0) { | 6892 for (int fn = 0; fn < ordered_functions; ++fn) { |
6918 // Only needed once. | 6893 int i = order[fn].index(); |
6919 join = graph()->CreateBasicBlock(); | 6894 Handle<Map> map = types->at(i); |
6920 if (handle_smi) { | 6895 if (fn == 0) { |
6921 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6896 // Only needed once. |
6922 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6897 join = graph()->CreateBasicBlock(); |
6923 number_block = graph()->CreateBasicBlock(); | 6898 if (handle_smi) { |
6924 FinishCurrentBlock( | 6899 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
6925 New<HIsSmiAndBranch>(receiver, empty_smi_block, not_smi_block)); | 6900 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
6926 Goto(empty_smi_block, number_block); | 6901 number_block = graph()->CreateBasicBlock(); |
6927 set_current_block(not_smi_block); | 6902 FinishCurrentBlock(New<HIsSmiAndBranch>( |
| 6903 receiver, empty_smi_block, not_smi_block)); |
| 6904 Goto(empty_smi_block, number_block); |
| 6905 set_current_block(not_smi_block); |
| 6906 } else { |
| 6907 BuildCheckHeapObject(receiver); |
| 6908 } |
| 6909 } |
| 6910 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 6911 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6912 HUnaryControlInstruction* compare; |
| 6913 |
| 6914 if (handle_smi && map.is_identical_to(number_marker_map)) { |
| 6915 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
| 6916 map = initial_number_map; |
| 6917 expr->set_number_check( |
| 6918 Handle<JSObject>(JSObject::cast(map->prototype()))); |
| 6919 } else if (map.is_identical_to(string_marker_map)) { |
| 6920 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
| 6921 map = initial_string_map; |
| 6922 expr->set_string_check( |
| 6923 Handle<JSObject>(JSObject::cast(map->prototype()))); |
6928 } else { | 6924 } else { |
6929 BuildCheckHeapObject(receiver); | 6925 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
6930 } | 6926 expr->set_map_check(); |
6931 } | |
6932 | |
6933 for (int fn = 0; fn < func_count; ++fn) { | |
6934 int i = order[fn].index(); | |
6935 FuncMapEntry* func_map_entry = &func_map[i]; | |
6936 | |
6937 HBasicBlock* call_block = graph()->CreateBasicBlock(); | |
6938 HBasicBlock* if_false = NULL; | |
6939 | |
6940 int maps_count = func_map_entry->maps.length(); | |
6941 for (int m = 0; m < maps_count; ++m) { | |
6942 Handle<Map> map = func_map_entry->maps.at(m); | |
6943 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
6944 if_false = graph()->CreateBasicBlock(); | |
6945 HUnaryControlInstruction* compare; | |
6946 | |
6947 if (handle_smi && map.is_identical_to(number_marker_map)) { | |
6948 compare = | |
6949 New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | |
6950 map = initial_number_map; | |
6951 expr->set_number_check( | |
6952 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
6953 } else if (map.is_identical_to(string_marker_map)) { | |
6954 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | |
6955 map = initial_string_map; | |
6956 expr->set_string_check( | |
6957 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
6958 } else { | |
6959 compare = New<HCompareMap>(receiver, map, if_true, if_false); | |
6960 expr->set_map_check(); | |
6961 } | |
6962 | |
6963 FinishCurrentBlock(compare); | |
6964 | |
6965 if (expr->check_type() == NUMBER_CHECK) { | |
6966 Goto(if_true, number_block); | |
6967 if_true = number_block; | |
6968 number_block->SetJoinId(expr->id()); | |
6969 } | |
6970 set_current_block(if_true); | |
6971 | |
6972 expr->ComputeTarget(map, name); | |
6973 ASSERT(*expr->target() == *func_map_entry->func); | |
6974 | |
6975 AddCheckPrototypeMaps(expr->holder(), map); | |
6976 | |
6977 Goto(if_true, call_block); | |
6978 | |
6979 set_current_block(if_false); | |
6980 } | 6927 } |
6981 | 6928 |
6982 // Generate call once for all corresponding maps. | 6929 FinishCurrentBlock(compare); |
6983 call_block->SetJoinId(expr->id()); | |
6984 set_current_block(call_block); | |
6985 | 6930 |
| 6931 if (expr->check_type() == NUMBER_CHECK) { |
| 6932 Goto(if_true, number_block); |
| 6933 if_true = number_block; |
| 6934 number_block->SetJoinId(expr->id()); |
| 6935 } |
| 6936 set_current_block(if_true); |
| 6937 |
| 6938 expr->ComputeTarget(map, name); |
| 6939 AddCheckPrototypeMaps(expr->holder(), map); |
6986 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 6940 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
6987 Handle<JSFunction> caller = current_info()->closure(); | 6941 Handle<JSFunction> caller = current_info()->closure(); |
6988 SmartArrayPointer<char> caller_name = | 6942 SmartArrayPointer<char> caller_name = |
6989 caller->shared()->DebugName()->ToCString(); | 6943 caller->shared()->DebugName()->ToCString(); |
6990 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6944 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
6991 name->ToCString().get(), | 6945 name->ToCString().get(), |
6992 caller_name.get()); | 6946 caller_name.get()); |
6993 } | 6947 } |
6994 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 6948 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
6995 // Trying to inline will signal that we should bailout from the | 6949 // Trying to inline will signal that we should bailout from the |
6996 // entire compilation by setting stack overflow on the visitor. | 6950 // entire compilation by setting stack overflow on the visitor. |
6997 if (HasStackOverflow()) return; | 6951 if (HasStackOverflow()) return; |
6998 } else { | 6952 } else { |
6999 HCallConstantFunction* call = | 6953 HCallConstantFunction* call = |
7000 New<HCallConstantFunction>(expr->target(), argument_count); | 6954 New<HCallConstantFunction>(expr->target(), argument_count); |
7001 PreProcessCall(call); | 6955 PreProcessCall(call); |
7002 AddInstruction(call); | 6956 AddInstruction(call); |
7003 if (!ast_context()->IsEffect()) Push(call); | 6957 if (!ast_context()->IsEffect()) Push(call); |
7004 } | 6958 } |
| 6959 |
7005 if (current_block() != NULL) Goto(join); | 6960 if (current_block() != NULL) Goto(join); |
7006 | |
7007 set_current_block(if_false); | 6961 set_current_block(if_false); |
7008 } | 6962 } |
7009 | 6963 |
7010 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 6964 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
7011 // know about and do not want to handle ones we've never seen. Otherwise | 6965 // know about and do not want to handle ones we've never seen. Otherwise |
7012 // use a generic IC. | 6966 // use a generic IC. |
7013 if (maps_count == types->length() && FLAG_deoptimize_uncommon_cases) { | 6967 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
7014 // Because the deopt may be the only path in the polymorphic call, make sure | 6968 // Because the deopt may be the only path in the polymorphic call, make sure |
7015 // that the environment stack matches the depth on deopt that it otherwise | 6969 // that the environment stack matches the depth on deopt that it otherwise |
7016 // would have had after a successful call. | 6970 // would have had after a successful call. |
7017 Drop(argument_count); | 6971 Drop(argument_count); |
7018 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 6972 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
7019 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); | 6973 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
7020 } else { | 6974 } else { |
7021 HCallNamed* call = New<HCallNamed>(name, argument_count); | 6975 HCallNamed* call = New<HCallNamed>(name, argument_count); |
7022 PreProcessCall(call); | 6976 PreProcessCall(call); |
7023 | 6977 |
(...skipping 3963 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10987 if (ShouldProduceTraceOutput()) { | 10941 if (ShouldProduceTraceOutput()) { |
10988 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10942 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
10989 } | 10943 } |
10990 | 10944 |
10991 #ifdef DEBUG | 10945 #ifdef DEBUG |
10992 graph_->Verify(false); // No full verify. | 10946 graph_->Verify(false); // No full verify. |
10993 #endif | 10947 #endif |
10994 } | 10948 } |
10995 | 10949 |
10996 } } // namespace v8::internal | 10950 } } // namespace v8::internal |
OLD | NEW |