| 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 3901 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3912 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand()); | 3912 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand()); |
| 3913 } else { | 3913 } else { |
| 3914 instruction->ReplaceAllUsesWith(instruction->ActualValue()); | 3914 instruction->ReplaceAllUsesWith(instruction->ActualValue()); |
| 3915 } | 3915 } |
| 3916 } | 3916 } |
| 3917 } | 3917 } |
| 3918 } | 3918 } |
| 3919 } | 3919 } |
| 3920 | 3920 |
| 3921 | 3921 |
| 3922 template <class Instruction> | 3922 void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) { |
| 3923 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { | |
| 3924 int count = call->argument_count(); | |
| 3925 ZoneList<HValue*> arguments(count, zone()); | 3923 ZoneList<HValue*> arguments(count, zone()); |
| 3926 for (int i = 0; i < count; ++i) { | 3924 for (int i = 0; i < count; ++i) { |
| 3927 arguments.Add(Pop(), zone()); | 3925 arguments.Add(Pop(), zone()); |
| 3928 } | 3926 } |
| 3929 | 3927 |
| 3930 while (!arguments.is_empty()) { | 3928 while (!arguments.is_empty()) { |
| 3931 Add<HPushArgument>(arguments.RemoveLast()); | 3929 Add<HPushArgument>(arguments.RemoveLast()); |
| 3932 } | 3930 } |
| 3931 } |
| 3932 |
| 3933 |
| 3934 template <class Instruction> |
| 3935 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { |
| 3936 PushArgumentsFromEnvironment(call->argument_count()); |
| 3933 return call; | 3937 return call; |
| 3934 } | 3938 } |
| 3935 | 3939 |
| 3936 | 3940 |
| 3937 void HOptimizedGraphBuilder::SetUpScope(Scope* scope) { | 3941 void HOptimizedGraphBuilder::SetUpScope(Scope* scope) { |
| 3938 // First special is HContext. | 3942 // First special is HContext. |
| 3939 HInstruction* context = Add<HContext>(); | 3943 HInstruction* context = Add<HContext>(); |
| 3940 environment()->BindContext(context); | 3944 environment()->BindContext(context); |
| 3941 | 3945 |
| 3942 // Create an arguments object containing the initial parameters. Set the | 3946 // Create an arguments object containing the initial parameters. Set the |
| (...skipping 1551 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5494 } | 5498 } |
| 5495 | 5499 |
| 5496 if (info->lookup()->IsPropertyCallbacks()) { | 5500 if (info->lookup()->IsPropertyCallbacks()) { |
| 5497 Push(checked_object); | 5501 Push(checked_object); |
| 5498 if (FLAG_inline_accessors && | 5502 if (FLAG_inline_accessors && |
| 5499 can_inline_accessor && | 5503 can_inline_accessor && |
| 5500 TryInlineGetter(info->accessor(), ast_id, return_id)) { | 5504 TryInlineGetter(info->accessor(), ast_id, return_id)) { |
| 5501 return NULL; | 5505 return NULL; |
| 5502 } | 5506 } |
| 5503 Add<HPushArgument>(Pop()); | 5507 Add<HPushArgument>(Pop()); |
| 5504 return New<HCallConstantFunction>(info->accessor(), 1); | 5508 return BuildCallConstantFunction(info->accessor(), 1); |
| 5505 } | 5509 } |
| 5506 | 5510 |
| 5507 ASSERT(info->lookup()->IsConstant()); | 5511 ASSERT(info->lookup()->IsConstant()); |
| 5508 return New<HConstant>(info->constant()); | 5512 return New<HConstant>(info->constant()); |
| 5509 } | 5513 } |
| 5510 | 5514 |
| 5511 | 5515 |
| 5512 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 5516 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
| 5513 BailoutId ast_id, | 5517 BailoutId ast_id, |
| 5514 BailoutId return_id, | 5518 BailoutId return_id, |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5779 Handle<JSObject> holder; | 5783 Handle<JSObject> holder; |
| 5780 if (LookupSetter(map, name, &setter, &holder)) { | 5784 if (LookupSetter(map, name, &setter, &holder)) { |
| 5781 AddCheckConstantFunction(holder, object, map); | 5785 AddCheckConstantFunction(holder, object, map); |
| 5782 if (FLAG_inline_accessors && | 5786 if (FLAG_inline_accessors && |
| 5783 TryInlineSetter(setter, ast_id, return_id, value)) { | 5787 TryInlineSetter(setter, ast_id, return_id, value)) { |
| 5784 return; | 5788 return; |
| 5785 } | 5789 } |
| 5786 Drop(2); | 5790 Drop(2); |
| 5787 Add<HPushArgument>(object); | 5791 Add<HPushArgument>(object); |
| 5788 Add<HPushArgument>(value); | 5792 Add<HPushArgument>(value); |
| 5789 instr = New<HCallConstantFunction>(setter, 2); | 5793 instr = BuildCallConstantFunction(setter, 2); |
| 5790 } else { | 5794 } else { |
| 5791 Drop(2); | 5795 Drop(2); |
| 5792 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 5796 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
| 5793 name, | 5797 name, |
| 5794 value, | 5798 value, |
| 5795 map)); | 5799 map)); |
| 5796 } | 5800 } |
| 5797 } else if (types != NULL && types->length() > 1) { | 5801 } else if (types != NULL && types->length() > 1) { |
| 5798 Drop(2); | 5802 Drop(2); |
| 5799 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); | 5803 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); |
| (...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6741 HValue* receiver, | 6745 HValue* receiver, |
| 6742 Handle<Map> receiver_map) { | 6746 Handle<Map> receiver_map) { |
| 6743 // Constant functions have the nice property that the map will change if they | 6747 // Constant functions have the nice property that the map will change if they |
| 6744 // are overwritten. Therefore it is enough to check the map of the holder and | 6748 // are overwritten. Therefore it is enough to check the map of the holder and |
| 6745 // its prototypes. | 6749 // its prototypes. |
| 6746 AddCheckMap(receiver, receiver_map); | 6750 AddCheckMap(receiver, receiver_map); |
| 6747 AddCheckPrototypeMaps(holder, receiver_map); | 6751 AddCheckPrototypeMaps(holder, receiver_map); |
| 6748 } | 6752 } |
| 6749 | 6753 |
| 6750 | 6754 |
| 6755 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( |
| 6756 HValue* fun, int argument_count, bool pass_argument_count) { |
| 6757 return New<HCallJSFunction>( |
| 6758 fun, argument_count, pass_argument_count); |
| 6759 } |
| 6760 |
| 6761 |
| 6762 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( |
| 6763 HValue* fun, HValue* context, |
| 6764 int argument_count, HValue* expected_param_count) { |
| 6765 CallInterfaceDescriptor* descriptor = |
| 6766 isolate()->call_descriptor(Isolate::ArgumentAdaptorCall); |
| 6767 |
| 6768 HValue* arity = Add<HConstant>(argument_count - 1); |
| 6769 |
| 6770 HValue* op_vals[] = { fun, context, arity, expected_param_count }; |
| 6771 |
| 6772 Handle<Code> adaptor = |
| 6773 isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 6774 HConstant* adaptor_value = Add<HConstant>(adaptor); |
| 6775 |
| 6776 return New<HCallWithDescriptor>( |
| 6777 adaptor_value, argument_count, descriptor, |
| 6778 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 6779 } |
| 6780 |
| 6781 |
| 6782 HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction( |
| 6783 Handle<JSFunction> jsfun, int argument_count) { |
| 6784 HValue* target = Add<HConstant>(jsfun); |
| 6785 // For constant functions, we try to avoid calling the |
| 6786 // argument adaptor and instead call the function directly |
| 6787 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); |
| 6788 bool dont_adapt_arguments = |
| 6789 (formal_parameter_count == |
| 6790 SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
| 6791 int arity = argument_count - 1; |
| 6792 bool can_invoke_directly = |
| 6793 dont_adapt_arguments || formal_parameter_count == arity; |
| 6794 if (can_invoke_directly) { |
| 6795 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); |
| 6796 } else { |
| 6797 HValue* param_count_value = Add<HConstant>(formal_parameter_count); |
| 6798 HValue* context = Add<HLoadNamedField>(target, |
| 6799 HObjectAccess::ForFunctionContextPointer()); |
| 6800 return NewArgumentAdaptorCall(target, context, |
| 6801 argument_count, param_count_value); |
| 6802 } |
| 6803 UNREACHABLE(); |
| 6804 return NULL; |
| 6805 } |
| 6806 |
| 6807 |
| 6808 HInstruction* HOptimizedGraphBuilder::NewCallNamed( |
| 6809 Handle<String> name, int argument_count) { |
| 6810 CallInterfaceDescriptor* descriptor = |
| 6811 isolate()->call_descriptor(Isolate::NamedCall); |
| 6812 HValue* op_vals[] = { context(), Add<HConstant>(name) }; |
| 6813 int arity = argument_count - 1; |
| 6814 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity); |
| 6815 |
| 6816 return New<HCallWithDescriptor>( |
| 6817 Add<HConstant>(ic), argument_count, descriptor, |
| 6818 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 6819 } |
| 6820 |
| 6821 |
| 6822 HInstruction* HOptimizedGraphBuilder::NewCallKeyed( |
| 6823 HValue* key, int argument_count) { |
| 6824 CallInterfaceDescriptor* descriptor = |
| 6825 isolate()->call_descriptor(Isolate::KeyedCall); |
| 6826 HValue* op_vals[] = { context(), key }; |
| 6827 int arity = argument_count - 1; |
| 6828 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); |
| 6829 |
| 6830 return New<HCallWithDescriptor>( |
| 6831 Add<HConstant>(ic), argument_count, descriptor, |
| 6832 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 6833 } |
| 6834 |
| 6751 class FunctionSorter { | 6835 class FunctionSorter { |
| 6752 public: | 6836 public: |
| 6753 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } | 6837 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } |
| 6754 FunctionSorter(int index, int ticks, int ast_length, int src_length) | 6838 FunctionSorter(int index, int ticks, int ast_length, int src_length) |
| 6755 : index_(index), | 6839 : index_(index), |
| 6756 ticks_(ticks), | 6840 ticks_(ticks), |
| 6757 ast_length_(ast_length), | 6841 ast_length_(ast_length), |
| 6758 src_length_(src_length) { } | 6842 src_length_(src_length) { } |
| 6759 | 6843 |
| 6760 int index() const { return index_; } | 6844 int index() const { return index_; } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6796 if (FLAG_trace_inlining) { | 6880 if (FLAG_trace_inlining) { |
| 6797 Handle<JSFunction> caller = current_info()->closure(); | 6881 Handle<JSFunction> caller = current_info()->closure(); |
| 6798 SmartArrayPointer<char> caller_name = | 6882 SmartArrayPointer<char> caller_name = |
| 6799 caller->shared()->DebugName()->ToCString(); | 6883 caller->shared()->DebugName()->ToCString(); |
| 6800 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6884 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
| 6801 name->ToCString().get(), caller_name.get()); | 6885 name->ToCString().get(), caller_name.get()); |
| 6802 } | 6886 } |
| 6803 | 6887 |
| 6804 if (!TryInlineCall(expr)) { | 6888 if (!TryInlineCall(expr)) { |
| 6805 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6889 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 6806 HCallConstantFunction* call = | 6890 HInstruction* call = BuildCallConstantFunction( |
| 6807 New<HCallConstantFunction>(expr->target(), argument_count); | 6891 expr->target(), argument_count); |
| 6808 PreProcessCall(call); | 6892 PushArgumentsFromEnvironment(argument_count); |
| 6809 AddInstruction(call); | 6893 AddInstruction(call); |
| 6810 if (!ast_context()->IsEffect()) Push(call); | 6894 if (!ast_context()->IsEffect()) Push(call); |
| 6811 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 6895 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 6812 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 6896 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 6813 } | 6897 } |
| 6814 | 6898 |
| 6815 return true; | 6899 return true; |
| 6816 } | 6900 } |
| 6817 | 6901 |
| 6818 | 6902 |
| 6819 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 6903 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
| 6820 Call* expr, | 6904 Call* expr, |
| 6821 HValue* receiver, | 6905 HValue* receiver, |
| 6822 SmallMapList* types, | 6906 SmallMapList* types, |
| 6823 Handle<String> name) { | 6907 Handle<String> name) { |
| 6824 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; | 6908 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; |
| 6825 | 6909 |
| 6826 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6910 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 6911 HBasicBlock* join = NULL; |
| 6912 FunctionSorter order[kMaxCallPolymorphism]; |
| 6913 int ordered_functions = 0; |
| 6827 | 6914 |
| 6828 Handle<Map> initial_string_map( | 6915 Handle<Map> initial_string_map( |
| 6829 isolate()->native_context()->string_function()->initial_map()); | 6916 isolate()->native_context()->string_function()->initial_map()); |
| 6830 Handle<Map> string_marker_map( | 6917 Handle<Map> string_marker_map( |
| 6831 JSObject::cast(initial_string_map->prototype())->map()); | 6918 JSObject::cast(initial_string_map->prototype())->map()); |
| 6832 Handle<Map> initial_number_map( | 6919 Handle<Map> initial_number_map( |
| 6833 isolate()->native_context()->number_function()->initial_map()); | 6920 isolate()->native_context()->number_function()->initial_map()); |
| 6834 Handle<Map> number_marker_map( | 6921 Handle<Map> number_marker_map( |
| 6835 JSObject::cast(initial_number_map->prototype())->map()); | 6922 JSObject::cast(initial_number_map->prototype())->map()); |
| 6836 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | 6923 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 6837 | 6924 |
| 6838 bool handle_smi = false; | 6925 bool handle_smi = false; |
| 6839 | 6926 |
| 6840 // A map from functions to a set of receivers' maps. | |
| 6841 struct FuncMapEntry { | |
| 6842 Handle<JSFunction> func; | |
| 6843 SmallMapList maps; | |
| 6844 }; | |
| 6845 FuncMapEntry func_map[kMaxCallPolymorphism]; | |
| 6846 FunctionSorter order[kMaxCallPolymorphism]; | |
| 6847 int func_count = 0; | |
| 6848 int maps_count = 0; | |
| 6849 | |
| 6850 for (int i = 0; | 6927 for (int i = 0; |
| 6851 i < types->length() && func_count < kMaxCallPolymorphism; | 6928 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
| 6852 ++i) { | 6929 ++i) { |
| 6853 Handle<Map> map = types->at(i); | 6930 Handle<Map> map = types->at(i); |
| 6854 if (expr->ComputeTarget(map, name)) { | 6931 if (expr->ComputeTarget(map, name)) { |
| 6855 if (map.is_identical_to(number_marker_map)) handle_smi = true; | 6932 if (map.is_identical_to(number_marker_map)) handle_smi = true; |
| 6856 | 6933 order[ordered_functions++] = |
| 6857 // Try to find the target function among known targets. | 6934 FunctionSorter(i, |
| 6858 int func_index = 0; | 6935 expr->target()->shared()->profiler_ticks(), |
| 6859 for (; func_index < func_count; ++func_index) { | 6936 InliningAstSize(expr->target()), |
| 6860 if (*func_map[func_index].func == *expr->target()) { | 6937 expr->target()->shared()->SourceSize()); |
| 6861 break; | |
| 6862 } | |
| 6863 } | |
| 6864 FuncMapEntry* entry = &func_map[func_index]; | |
| 6865 if (func_index == func_count) { | |
| 6866 // Entry not found, "allocate" it. | |
| 6867 entry->func = expr->target(); | |
| 6868 entry->maps.Reserve(types->length() - maps_count, zone()); | |
| 6869 order[func_index] = | |
| 6870 FunctionSorter(func_index, | |
| 6871 entry->func->shared()->profiler_ticks(), | |
| 6872 InliningAstSize(entry->func), | |
| 6873 entry->func->shared()->SourceSize()); | |
| 6874 ++func_count; | |
| 6875 } | |
| 6876 entry->maps.Add(map, zone()); | |
| 6877 ++maps_count; | |
| 6878 } | 6938 } |
| 6879 } | 6939 } |
| 6880 | 6940 |
| 6881 std::sort(order, order + func_count); | 6941 std::sort(order, order + ordered_functions); |
| 6882 | 6942 |
| 6883 HBasicBlock* number_block = NULL; | 6943 HBasicBlock* number_block = NULL; |
| 6884 HBasicBlock* join = NULL; | |
| 6885 | 6944 |
| 6886 if (func_count > 0) { | 6945 for (int fn = 0; fn < ordered_functions; ++fn) { |
| 6887 // Only needed once. | 6946 int i = order[fn].index(); |
| 6888 join = graph()->CreateBasicBlock(); | 6947 Handle<Map> map = types->at(i); |
| 6889 if (handle_smi) { | 6948 if (fn == 0) { |
| 6890 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6949 // Only needed once. |
| 6891 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6950 join = graph()->CreateBasicBlock(); |
| 6892 number_block = graph()->CreateBasicBlock(); | 6951 if (handle_smi) { |
| 6893 FinishCurrentBlock( | 6952 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 6894 New<HIsSmiAndBranch>(receiver, empty_smi_block, not_smi_block)); | 6953 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 6895 Goto(empty_smi_block, number_block); | 6954 number_block = graph()->CreateBasicBlock(); |
| 6896 set_current_block(not_smi_block); | 6955 FinishCurrentBlock(New<HIsSmiAndBranch>( |
| 6956 receiver, empty_smi_block, not_smi_block)); |
| 6957 Goto(empty_smi_block, number_block); |
| 6958 set_current_block(not_smi_block); |
| 6959 } else { |
| 6960 BuildCheckHeapObject(receiver); |
| 6961 } |
| 6962 } |
| 6963 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 6964 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6965 HUnaryControlInstruction* compare; |
| 6966 |
| 6967 if (handle_smi && map.is_identical_to(number_marker_map)) { |
| 6968 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
| 6969 map = initial_number_map; |
| 6970 expr->set_number_check( |
| 6971 Handle<JSObject>(JSObject::cast(map->prototype()))); |
| 6972 } else if (map.is_identical_to(string_marker_map)) { |
| 6973 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
| 6974 map = initial_string_map; |
| 6975 expr->set_string_check( |
| 6976 Handle<JSObject>(JSObject::cast(map->prototype()))); |
| 6897 } else { | 6977 } else { |
| 6898 BuildCheckHeapObject(receiver); | 6978 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
| 6899 } | 6979 expr->set_map_check(); |
| 6900 } | |
| 6901 | |
| 6902 for (int fn = 0; fn < func_count; ++fn) { | |
| 6903 int i = order[fn].index(); | |
| 6904 FuncMapEntry* func_map_entry = &func_map[i]; | |
| 6905 | |
| 6906 HBasicBlock* call_block = graph()->CreateBasicBlock(); | |
| 6907 HBasicBlock* if_false = NULL; | |
| 6908 | |
| 6909 int maps_count = func_map_entry->maps.length(); | |
| 6910 for (int m = 0; m < maps_count; ++m) { | |
| 6911 Handle<Map> map = func_map_entry->maps.at(m); | |
| 6912 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
| 6913 if_false = graph()->CreateBasicBlock(); | |
| 6914 HUnaryControlInstruction* compare; | |
| 6915 | |
| 6916 if (handle_smi && map.is_identical_to(number_marker_map)) { | |
| 6917 compare = | |
| 6918 New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | |
| 6919 map = initial_number_map; | |
| 6920 expr->set_number_check( | |
| 6921 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
| 6922 } else if (map.is_identical_to(string_marker_map)) { | |
| 6923 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | |
| 6924 map = initial_string_map; | |
| 6925 expr->set_string_check( | |
| 6926 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
| 6927 } else { | |
| 6928 compare = New<HCompareMap>(receiver, map, if_true, if_false); | |
| 6929 expr->set_map_check(); | |
| 6930 } | |
| 6931 | |
| 6932 FinishCurrentBlock(compare); | |
| 6933 | |
| 6934 if (expr->check_type() == NUMBER_CHECK) { | |
| 6935 Goto(if_true, number_block); | |
| 6936 if_true = number_block; | |
| 6937 number_block->SetJoinId(expr->id()); | |
| 6938 } | |
| 6939 set_current_block(if_true); | |
| 6940 | |
| 6941 expr->ComputeTarget(map, name); | |
| 6942 ASSERT(*expr->target() == *func_map_entry->func); | |
| 6943 | |
| 6944 AddCheckPrototypeMaps(expr->holder(), map); | |
| 6945 | |
| 6946 Goto(if_true, call_block); | |
| 6947 | |
| 6948 set_current_block(if_false); | |
| 6949 } | 6980 } |
| 6950 | 6981 |
| 6951 // Generate call once for all corresponding maps. | 6982 FinishCurrentBlock(compare); |
| 6952 call_block->SetJoinId(expr->id()); | |
| 6953 set_current_block(call_block); | |
| 6954 | 6983 |
| 6984 if (expr->check_type() == NUMBER_CHECK) { |
| 6985 Goto(if_true, number_block); |
| 6986 if_true = number_block; |
| 6987 number_block->SetJoinId(expr->id()); |
| 6988 } |
| 6989 set_current_block(if_true); |
| 6990 |
| 6991 expr->ComputeTarget(map, name); |
| 6992 AddCheckPrototypeMaps(expr->holder(), map); |
| 6955 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 6993 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { |
| 6956 Handle<JSFunction> caller = current_info()->closure(); | 6994 Handle<JSFunction> caller = current_info()->closure(); |
| 6957 SmartArrayPointer<char> caller_name = | 6995 SmartArrayPointer<char> caller_name = |
| 6958 caller->shared()->DebugName()->ToCString(); | 6996 caller->shared()->DebugName()->ToCString(); |
| 6959 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6997 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
| 6960 name->ToCString().get(), | 6998 name->ToCString().get(), |
| 6961 caller_name.get()); | 6999 caller_name.get()); |
| 6962 } | 7000 } |
| 6963 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 7001 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { |
| 6964 // Trying to inline will signal that we should bailout from the | 7002 // Trying to inline will signal that we should bailout from the |
| 6965 // entire compilation by setting stack overflow on the visitor. | 7003 // entire compilation by setting stack overflow on the visitor. |
| 6966 if (HasStackOverflow()) return; | 7004 if (HasStackOverflow()) return; |
| 6967 } else { | 7005 } else { |
| 6968 HCallConstantFunction* call = | 7006 HInstruction* call = BuildCallConstantFunction( |
| 6969 New<HCallConstantFunction>(expr->target(), argument_count); | 7007 expr->target(), argument_count); |
| 6970 PreProcessCall(call); | 7008 PushArgumentsFromEnvironment(argument_count); |
| 6971 AddInstruction(call); | 7009 AddInstruction(call); |
| 6972 if (!ast_context()->IsEffect()) Push(call); | 7010 if (!ast_context()->IsEffect()) Push(call); |
| 6973 } | 7011 } |
| 7012 |
| 6974 if (current_block() != NULL) Goto(join); | 7013 if (current_block() != NULL) Goto(join); |
| 6975 | |
| 6976 set_current_block(if_false); | 7014 set_current_block(if_false); |
| 6977 } | 7015 } |
| 6978 | 7016 |
| 6979 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 7017 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 6980 // know about and do not want to handle ones we've never seen. Otherwise | 7018 // know about and do not want to handle ones we've never seen. Otherwise |
| 6981 // use a generic IC. | 7019 // use a generic IC. |
| 6982 if (maps_count == types->length() && FLAG_deoptimize_uncommon_cases) { | 7020 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 6983 // Because the deopt may be the only path in the polymorphic call, make sure | 7021 // Because the deopt may be the only path in the polymorphic call, make sure |
| 6984 // that the environment stack matches the depth on deopt that it otherwise | 7022 // that the environment stack matches the depth on deopt that it otherwise |
| 6985 // would have had after a successful call. | 7023 // would have had after a successful call. |
| 6986 Drop(argument_count); | 7024 Drop(argument_count); |
| 6987 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 7025 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
| 6988 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); | 7026 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
| 6989 } else { | 7027 } else { |
| 6990 HCallNamed* call = New<HCallNamed>(name, argument_count); | 7028 HInstruction* call = NewCallNamed(name, argument_count); |
| 6991 PreProcessCall(call); | 7029 PushArgumentsFromEnvironment(argument_count); |
| 6992 | 7030 |
| 6993 if (join != NULL) { | 7031 if (join != NULL) { |
| 6994 AddInstruction(call); | 7032 AddInstruction(call); |
| 6995 if (!ast_context()->IsEffect()) Push(call); | 7033 if (!ast_context()->IsEffect()) Push(call); |
| 6996 Goto(join); | 7034 Goto(join); |
| 6997 } else { | 7035 } else { |
| 6998 return ast_context()->ReturnInstruction(call, expr->id()); | 7036 return ast_context()->ReturnInstruction(call, expr->id()); |
| 6999 } | 7037 } |
| 7000 } | 7038 } |
| 7001 | 7039 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7064 if (target_shared->dont_inline() || target_shared->dont_optimize()) { | 7102 if (target_shared->dont_inline() || target_shared->dont_optimize()) { |
| 7065 TraceInline(target, caller, "target contains unsupported syntax [early]"); | 7103 TraceInline(target, caller, "target contains unsupported syntax [early]"); |
| 7066 return kNotInlinable; | 7104 return kNotInlinable; |
| 7067 } | 7105 } |
| 7068 | 7106 |
| 7069 int nodes_added = target_shared->ast_node_count(); | 7107 int nodes_added = target_shared->ast_node_count(); |
| 7070 return nodes_added; | 7108 return nodes_added; |
| 7071 } | 7109 } |
| 7072 | 7110 |
| 7073 | 7111 |
| 7074 bool HOptimizedGraphBuilder::TryInline(CallKind call_kind, | 7112 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
| 7075 Handle<JSFunction> target, | |
| 7076 int arguments_count, | 7113 int arguments_count, |
| 7077 HValue* implicit_return_value, | 7114 HValue* implicit_return_value, |
| 7078 BailoutId ast_id, | 7115 BailoutId ast_id, |
| 7079 BailoutId return_id, | 7116 BailoutId return_id, |
| 7080 InliningKind inlining_kind) { | 7117 InliningKind inlining_kind) { |
| 7081 int nodes_added = InliningAstSize(target); | 7118 int nodes_added = InliningAstSize(target); |
| 7082 if (nodes_added == kNotInlinable) return false; | 7119 if (nodes_added == kNotInlinable) return false; |
| 7083 | 7120 |
| 7084 Handle<JSFunction> caller = current_info()->closure(); | 7121 Handle<JSFunction> caller = current_info()->closure(); |
| 7085 | 7122 |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7365 set_current_block(function_return()); | 7402 set_current_block(function_return()); |
| 7366 } else { | 7403 } else { |
| 7367 set_current_block(NULL); | 7404 set_current_block(NULL); |
| 7368 } | 7405 } |
| 7369 delete target_state; | 7406 delete target_state; |
| 7370 return true; | 7407 return true; |
| 7371 } | 7408 } |
| 7372 | 7409 |
| 7373 | 7410 |
| 7374 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { | 7411 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { |
| 7375 // The function call we are inlining is a method call if the call | 7412 return TryInline(expr->target(), |
| 7376 // is a property call. | |
| 7377 CallKind call_kind = (expr->expression()->AsProperty() == NULL) | |
| 7378 ? CALL_AS_FUNCTION | |
| 7379 : CALL_AS_METHOD; | |
| 7380 | |
| 7381 return TryInline(call_kind, | |
| 7382 expr->target(), | |
| 7383 expr->arguments()->length(), | 7413 expr->arguments()->length(), |
| 7384 NULL, | 7414 NULL, |
| 7385 expr->id(), | 7415 expr->id(), |
| 7386 expr->ReturnId(), | 7416 expr->ReturnId(), |
| 7387 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); | 7417 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); |
| 7388 } | 7418 } |
| 7389 | 7419 |
| 7390 | 7420 |
| 7391 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, | 7421 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
| 7392 HValue* implicit_return_value) { | 7422 HValue* implicit_return_value) { |
| 7393 return TryInline(CALL_AS_FUNCTION, | 7423 return TryInline(expr->target(), |
| 7394 expr->target(), | |
| 7395 expr->arguments()->length(), | 7424 expr->arguments()->length(), |
| 7396 implicit_return_value, | 7425 implicit_return_value, |
| 7397 expr->id(), | 7426 expr->id(), |
| 7398 expr->ReturnId(), | 7427 expr->ReturnId(), |
| 7399 CONSTRUCT_CALL_RETURN); | 7428 CONSTRUCT_CALL_RETURN); |
| 7400 } | 7429 } |
| 7401 | 7430 |
| 7402 | 7431 |
| 7403 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, | 7432 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, |
| 7404 BailoutId ast_id, | 7433 BailoutId ast_id, |
| 7405 BailoutId return_id) { | 7434 BailoutId return_id) { |
| 7406 return TryInline(CALL_AS_METHOD, | 7435 return TryInline(getter, |
| 7407 getter, | |
| 7408 0, | 7436 0, |
| 7409 NULL, | 7437 NULL, |
| 7410 ast_id, | 7438 ast_id, |
| 7411 return_id, | 7439 return_id, |
| 7412 GETTER_CALL_RETURN); | 7440 GETTER_CALL_RETURN); |
| 7413 } | 7441 } |
| 7414 | 7442 |
| 7415 | 7443 |
| 7416 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, | 7444 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
| 7417 BailoutId id, | 7445 BailoutId id, |
| 7418 BailoutId assignment_id, | 7446 BailoutId assignment_id, |
| 7419 HValue* implicit_return_value) { | 7447 HValue* implicit_return_value) { |
| 7420 return TryInline(CALL_AS_METHOD, | 7448 return TryInline(setter, |
| 7421 setter, | |
| 7422 1, | 7449 1, |
| 7423 implicit_return_value, | 7450 implicit_return_value, |
| 7424 id, assignment_id, | 7451 id, assignment_id, |
| 7425 SETTER_CALL_RETURN); | 7452 SETTER_CALL_RETURN); |
| 7426 } | 7453 } |
| 7427 | 7454 |
| 7428 | 7455 |
| 7429 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, | 7456 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
| 7430 Call* expr, | 7457 Call* expr, |
| 7431 int arguments_count) { | 7458 int arguments_count) { |
| 7432 return TryInline(CALL_AS_METHOD, | 7459 return TryInline(function, |
| 7433 function, | |
| 7434 arguments_count, | 7460 arguments_count, |
| 7435 NULL, | 7461 NULL, |
| 7436 expr->id(), | 7462 expr->id(), |
| 7437 expr->ReturnId(), | 7463 expr->ReturnId(), |
| 7438 NORMAL_RETURN); | 7464 NORMAL_RETURN); |
| 7439 } | 7465 } |
| 7440 | 7466 |
| 7441 | 7467 |
| 7442 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, | 7468 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, |
| 7443 bool drop_extra) { | 7469 bool drop_extra) { |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7734 ElementsKind kind = expr->KeyedArrayCallIsHoley() | 7760 ElementsKind kind = expr->KeyedArrayCallIsHoley() |
| 7735 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; | 7761 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
| 7736 | 7762 |
| 7737 Handle<Map> map(isolate()->get_initial_js_array_map(kind)); | 7763 Handle<Map> map(isolate()->get_initial_js_array_map(kind)); |
| 7738 | 7764 |
| 7739 HValue* function = BuildMonomorphicElementAccess( | 7765 HValue* function = BuildMonomorphicElementAccess( |
| 7740 receiver, key, NULL, NULL, map, false, STANDARD_STORE); | 7766 receiver, key, NULL, NULL, map, false, STANDARD_STORE); |
| 7741 | 7767 |
| 7742 call = New<HCallFunction>(function, argument_count); | 7768 call = New<HCallFunction>(function, argument_count); |
| 7743 } else { | 7769 } else { |
| 7744 call = New<HCallKeyed>(key, argument_count); | 7770 call = NewCallKeyed(key, argument_count); |
| 7745 } | 7771 } |
| 7746 Drop(argument_count + 1); // 1 is the key. | 7772 Drop(argument_count + 1); // 1 is the key. |
| 7747 return ast_context()->ReturnInstruction(call, expr->id()); | 7773 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7748 } | 7774 } |
| 7749 | 7775 |
| 7750 // Named function call. | 7776 // Named function call. |
| 7751 if (TryCallApply(expr)) return; | 7777 if (TryCallApply(expr)) return; |
| 7752 | 7778 |
| 7753 CHECK_ALIVE(VisitForValue(prop->obj())); | 7779 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7754 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 7780 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 7773 PrintF("\n"); | 7799 PrintF("\n"); |
| 7774 } | 7800 } |
| 7775 return; | 7801 return; |
| 7776 } | 7802 } |
| 7777 | 7803 |
| 7778 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || | 7804 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || |
| 7779 expr->check_type() != RECEIVER_MAP_CHECK) { | 7805 expr->check_type() != RECEIVER_MAP_CHECK) { |
| 7780 // When the target has a custom call IC generator, use the IC, | 7806 // When the target has a custom call IC generator, use the IC, |
| 7781 // because it is likely to generate better code. Also use the IC | 7807 // because it is likely to generate better code. Also use the IC |
| 7782 // when a primitive receiver check is required. | 7808 // when a primitive receiver check is required. |
| 7783 call = PreProcessCall(New<HCallNamed>(name, argument_count)); | 7809 call = NewCallNamed(name, argument_count); |
| 7810 PushArgumentsFromEnvironment(argument_count); |
| 7784 } else { | 7811 } else { |
| 7785 AddCheckConstantFunction(expr->holder(), receiver, map); | 7812 AddCheckConstantFunction(expr->holder(), receiver, map); |
| 7786 | 7813 |
| 7787 if (TryInlineCall(expr)) return; | 7814 if (TryInlineCall(expr)) return; |
| 7788 call = PreProcessCall( | 7815 call = BuildCallConstantFunction(expr->target(), argument_count); |
| 7789 New<HCallConstantFunction>(expr->target(), argument_count)); | 7816 PushArgumentsFromEnvironment(argument_count); |
| 7790 } | 7817 } |
| 7791 } else if (types != NULL && types->length() > 1) { | 7818 } else if (types != NULL && types->length() > 1) { |
| 7792 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | 7819 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); |
| 7793 HandlePolymorphicCallNamed(expr, receiver, types, name); | 7820 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 7794 return; | 7821 return; |
| 7795 | 7822 |
| 7796 } else { | 7823 } else { |
| 7797 call = PreProcessCall(New<HCallNamed>(name, argument_count)); | 7824 call = NewCallNamed(name, argument_count); |
| 7825 PushArgumentsFromEnvironment(argument_count); |
| 7798 } | 7826 } |
| 7799 } else { | 7827 } else { |
| 7800 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 7828 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 7801 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 7829 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
| 7802 return Bailout(kPossibleDirectCallToEval); | 7830 return Bailout(kPossibleDirectCallToEval); |
| 7803 } | 7831 } |
| 7804 | 7832 |
| 7805 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 7833 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
| 7806 if (global_call) { | 7834 if (global_call) { |
| 7807 Variable* var = proxy->var(); | 7835 Variable* var = proxy->var(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7848 } | 7876 } |
| 7849 | 7877 |
| 7850 if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { | 7878 if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { |
| 7851 // We're about to install a contextual IC, which expects the global | 7879 // We're about to install a contextual IC, which expects the global |
| 7852 // object as receiver rather than the global proxy. | 7880 // object as receiver rather than the global proxy. |
| 7853 HGlobalObject* global_object = Add<HGlobalObject>(); | 7881 HGlobalObject* global_object = Add<HGlobalObject>(); |
| 7854 const int receiver_index = argument_count - 1; | 7882 const int receiver_index = argument_count - 1; |
| 7855 environment()->SetExpressionStackAt(receiver_index, global_object); | 7883 environment()->SetExpressionStackAt(receiver_index, global_object); |
| 7856 // When the target has a custom call IC generator, use the IC, | 7884 // When the target has a custom call IC generator, use the IC, |
| 7857 // because it is likely to generate better code. | 7885 // because it is likely to generate better code. |
| 7858 call = PreProcessCall(New<HCallGlobal>(var->name(), argument_count)); | 7886 call = NewCallNamed(var->name(), argument_count); |
| 7887 PushArgumentsFromEnvironment(argument_count); |
| 7859 } else { | 7888 } else { |
| 7860 call = PreProcessCall(New<HCallKnownGlobal>( | 7889 call = BuildCallConstantFunction(expr->target(), argument_count); |
| 7861 expr->target(), argument_count)); | 7890 PushArgumentsFromEnvironment(argument_count); |
| 7862 } | 7891 } |
| 7863 } else { | 7892 } else { |
| 7864 HGlobalObject* receiver = Add<HGlobalObject>(); | 7893 HGlobalObject* receiver = Add<HGlobalObject>(); |
| 7865 Push(Add<HPushArgument>(receiver)); | 7894 Push(Add<HPushArgument>(receiver)); |
| 7866 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 7895 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 7867 | 7896 |
| 7868 call = New<HCallGlobal>(var->name(), argument_count); | 7897 call = NewCallNamed(var->name(), argument_count); |
| 7869 Drop(argument_count); | 7898 Drop(argument_count); |
| 7870 } | 7899 } |
| 7871 | 7900 |
| 7872 } else if (expr->IsMonomorphic()) { | 7901 } else if (expr->IsMonomorphic()) { |
| 7873 // The function is on the stack in the unoptimized code during | 7902 // The function is on the stack in the unoptimized code during |
| 7874 // evaluation of the arguments. | 7903 // evaluation of the arguments. |
| 7875 CHECK_ALIVE(VisitForValue(expr->expression())); | 7904 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7876 HValue* function = Top(); | 7905 HValue* function = Top(); |
| 7877 | 7906 |
| 7878 Add<HCheckValue>(function, expr->target()); | 7907 Add<HCheckValue>(function, expr->target()); |
| (...skipping 3106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10985 if (ShouldProduceTraceOutput()) { | 11014 if (ShouldProduceTraceOutput()) { |
| 10986 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11015 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10987 } | 11016 } |
| 10988 | 11017 |
| 10989 #ifdef DEBUG | 11018 #ifdef DEBUG |
| 10990 graph_->Verify(false); // No full verify. | 11019 graph_->Verify(false); // No full verify. |
| 10991 #endif | 11020 #endif |
| 10992 } | 11021 } |
| 10993 | 11022 |
| 10994 } } // namespace v8::internal | 11023 } } // namespace v8::internal |
| OLD | NEW |