 Chromium Code Reviews
 Chromium Code Reviews Issue 118483003:
  Polymorphic named calls optimized for the case of repetitive call targets.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 118483003:
  Polymorphic named calls optimized for the case of repetitive call targets.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| 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 |