| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 761 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 IC::UtilityId id) { | 772 IC::UtilityId id) { |
| 773 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); | 773 PushInterceptorArguments(masm, receiver, holder, name, holder_obj); |
| 774 __ CallExternalReference( | 774 __ CallExternalReference( |
| 775 ExternalReference(IC_Utility(id), masm->isolate()), | 775 ExternalReference(IC_Utility(id), masm->isolate()), |
| 776 StubCache::kInterceptorArgsLength); | 776 StubCache::kInterceptorArgsLength); |
| 777 } | 777 } |
| 778 | 778 |
| 779 | 779 |
| 780 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; | 780 static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; |
| 781 | 781 |
| 782 // Reserves space for the extra arguments to API function in the |
| 783 // caller's frame. |
| 784 // |
| 785 // These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. |
| 786 static void ReserveSpaceForFastApiCall(MacroAssembler* masm, |
| 787 Register scratch) { |
| 788 __ mov(scratch, Operand(Smi::FromInt(0))); |
| 789 for (int i = 0; i < kFastApiCallArguments; i++) { |
| 790 __ push(scratch); |
| 791 } |
| 792 } |
| 782 | 793 |
| 783 static void GenerateFastApiCallBody(MacroAssembler* masm, | 794 |
| 784 const CallOptimization& optimization, | 795 // Undoes the effects of ReserveSpaceForFastApiCall. |
| 785 int argc, | 796 static void FreeSpaceForFastApiCall(MacroAssembler* masm) { |
| 786 Register holder, | 797 __ Drop(kFastApiCallArguments); |
| 787 Register scratch1, | 798 } |
| 788 Register scratch2, | 799 |
| 789 Register scratch3, | 800 |
| 790 bool restore_context) { | 801 static void GenerateFastApiDirectCall(MacroAssembler* masm, |
| 802 const CallOptimization& optimization, |
| 803 int argc, |
| 804 bool restore_context) { |
| 791 // ----------- S t a t e ------------- | 805 // ----------- S t a t e ------------- |
| 792 // -- sp[0] : last JS argument | 806 // -- sp[0] - sp[24] : FunctionCallbackInfo, incl. |
| 807 // : holder (set by CheckPrototypes) |
| 808 // -- sp[28] : last JS argument |
| 793 // -- ... | 809 // -- ... |
| 794 // -- sp[(argc - 1) * 4] : first JS argument | 810 // -- sp[(argc + 6) * 4] : first JS argument |
| 795 // -- sp[argc * 4] : receiver | 811 // -- sp[(argc + 7) * 4] : receiver |
| 796 // ----------------------------------- | 812 // ----------------------------------- |
| 797 ASSERT(optimization.is_simple_api_call()); | |
| 798 | |
| 799 typedef FunctionCallbackArguments FCA; | 813 typedef FunctionCallbackArguments FCA; |
| 800 | |
| 801 STATIC_ASSERT(FCA::kHolderIndex == 0); | |
| 802 STATIC_ASSERT(FCA::kIsolateIndex == 1); | |
| 803 STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); | |
| 804 STATIC_ASSERT(FCA::kReturnValueOffset == 3); | |
| 805 STATIC_ASSERT(FCA::kDataIndex == 4); | |
| 806 STATIC_ASSERT(FCA::kCalleeIndex == 5); | |
| 807 STATIC_ASSERT(FCA::kContextSaveIndex == 6); | |
| 808 STATIC_ASSERT(FCA::kArgsLength == 7); | |
| 809 | |
| 810 ASSERT(!holder.is(cp)); | |
| 811 | |
| 812 // Save calling context. | 814 // Save calling context. |
| 813 __ push(cp); | 815 __ str(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize)); |
| 814 // Get the function and setup the context. | 816 // Get the function and setup the context. |
| 815 Handle<JSFunction> function = optimization.constant_function(); | 817 Handle<JSFunction> function = optimization.constant_function(); |
| 816 __ Move(scratch1, function); | 818 __ Move(r5, function); |
| 817 __ ldr(cp, FieldMemOperand(scratch1, JSFunction::kContextOffset)); | 819 __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); |
| 818 __ push(scratch1); | 820 __ str(r5, MemOperand(sp, FCA::kCalleeIndex * kPointerSize)); |
| 819 | 821 |
| 820 // Construct the FunctionCallbackInfo. | 822 // Construct the FunctionCallbackInfo. |
| 821 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 823 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 822 Handle<Object> call_data(api_call_info->data(), masm->isolate()); | 824 Handle<Object> call_data(api_call_info->data(), masm->isolate()); |
| 823 bool call_data_undefined = false; | |
| 824 if (masm->isolate()->heap()->InNewSpace(*call_data)) { | 825 if (masm->isolate()->heap()->InNewSpace(*call_data)) { |
| 825 __ Move(scratch1, api_call_info); | 826 __ Move(r0, api_call_info); |
| 826 __ ldr(scratch1, FieldMemOperand(scratch1, CallHandlerInfo::kDataOffset)); | 827 __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); |
| 827 } else if (call_data->IsUndefined()) { | |
| 828 call_data_undefined = true; | |
| 829 __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); | |
| 830 } else { | 828 } else { |
| 831 __ Move(scratch1, call_data); | 829 __ Move(r6, call_data); |
| 832 } | 830 } |
| 833 // Store call data. | 831 // Store call data. |
| 834 __ push(scratch1); | 832 __ str(r6, MemOperand(sp, FCA::kDataIndex * kPointerSize)); |
| 835 if (!call_data_undefined) { | 833 // Store isolate. |
| 836 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); | 834 __ mov(r5, Operand(ExternalReference::isolate_address(masm->isolate()))); |
| 837 } | 835 __ str(r5, MemOperand(sp, FCA::kIsolateIndex * kPointerSize)); |
| 838 // Store ReturnValue default and ReturnValue. | 836 // Store ReturnValue default and ReturnValue. |
| 839 __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); | 837 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); |
| 840 __ push(scratch1); | 838 __ str(r5, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize)); |
| 841 __ push(scratch1); | 839 __ str(r5, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize)); |
| 842 // Store isolate. | |
| 843 __ mov(scratch1, | |
| 844 Operand(ExternalReference::isolate_address(masm->isolate()))); | |
| 845 __ push(scratch1); | |
| 846 // holder | |
| 847 __ push(holder); | |
| 848 | 840 |
| 849 // Prepare arguments. | 841 // Prepare arguments. |
| 850 __ mov(r2, sp); | 842 __ mov(r2, sp); |
| 851 | 843 |
| 852 // Allocate the v8::Arguments structure in the arguments' space since | 844 // Allocate the v8::Arguments structure in the arguments' space since |
| 853 // it's not controlled by GC. | 845 // it's not controlled by GC. |
| 854 const int kApiStackSpace = 4; | 846 const int kApiStackSpace = 4; |
| 855 | 847 |
| 856 FrameScope frame_scope(masm, StackFrame::MANUAL); | 848 FrameScope frame_scope(masm, StackFrame::MANUAL); |
| 857 __ EnterExitFrame(false, kApiStackSpace); | 849 __ EnterExitFrame(false, kApiStackSpace); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 function_address, | 886 function_address, |
| 895 thunk_ref, | 887 thunk_ref, |
| 896 r1, | 888 r1, |
| 897 kStackUnwindSpace, | 889 kStackUnwindSpace, |
| 898 return_value_operand, | 890 return_value_operand, |
| 899 restore_context ? | 891 restore_context ? |
| 900 &context_restore_operand : NULL); | 892 &context_restore_operand : NULL); |
| 901 } | 893 } |
| 902 | 894 |
| 903 | 895 |
| 904 // Generates call to API function. | |
| 905 static void GenerateFastApiCall(MacroAssembler* masm, | |
| 906 const CallOptimization& optimization, | |
| 907 int argc, | |
| 908 Handle<Map> map_to_holder, | |
| 909 CallOptimization::HolderLookup holder_lookup) { | |
| 910 Counters* counters = masm->isolate()->counters(); | |
| 911 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r1); | |
| 912 | |
| 913 // Move holder to a register | |
| 914 Register holder_reg = r0; | |
| 915 switch (holder_lookup) { | |
| 916 case CallOptimization::kHolderIsReceiver: | |
| 917 { | |
| 918 ASSERT(map_to_holder.is_null()); | |
| 919 __ ldr(holder_reg, MemOperand(sp, argc * kPointerSize)); | |
| 920 } | |
| 921 break; | |
| 922 case CallOptimization::kHolderIsPrototypeOfMap: | |
| 923 { | |
| 924 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); | |
| 925 if (!masm->isolate()->heap()->InNewSpace(*holder)) { | |
| 926 __ Move(holder_reg, holder); | |
| 927 } else { | |
| 928 __ Move(holder_reg, map_to_holder); | |
| 929 __ ldr(holder_reg, | |
| 930 FieldMemOperand(holder_reg, Map::kPrototypeOffset)); | |
| 931 } | |
| 932 } | |
| 933 break; | |
| 934 case CallOptimization::kHolderNotFound: | |
| 935 UNREACHABLE(); | |
| 936 } | |
| 937 GenerateFastApiCallBody(masm, | |
| 938 optimization, | |
| 939 argc, | |
| 940 holder_reg, | |
| 941 r1, | |
| 942 r2, | |
| 943 r3, | |
| 944 false); | |
| 945 } | |
| 946 | |
| 947 | |
| 948 // Generate call to api function. | 896 // Generate call to api function. |
| 949 static void GenerateFastApiCall(MacroAssembler* masm, | 897 static void GenerateFastApiCall(MacroAssembler* masm, |
| 950 const CallOptimization& optimization, | 898 const CallOptimization& optimization, |
| 951 Register receiver, | 899 Register receiver, |
| 952 Register scratch, | 900 Register scratch, |
| 953 int argc, | 901 int argc, |
| 954 Register* values) { | 902 Register* values) { |
| 903 ASSERT(optimization.is_simple_api_call()); |
| 955 ASSERT(!receiver.is(scratch)); | 904 ASSERT(!receiver.is(scratch)); |
| 956 __ push(receiver); | 905 |
| 906 typedef FunctionCallbackArguments FCA; |
| 907 const int stack_space = kFastApiCallArguments + argc + 1; |
| 908 // Assign stack space for the call arguments. |
| 909 __ sub(sp, sp, Operand(stack_space * kPointerSize)); |
| 910 // Write holder to stack frame. |
| 911 __ str(receiver, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); |
| 912 // Write receiver to stack frame. |
| 913 int index = stack_space - 1; |
| 914 __ str(receiver, MemOperand(sp, index-- * kPointerSize)); |
| 957 // Write the arguments to stack frame. | 915 // Write the arguments to stack frame. |
| 958 for (int i = 0; i < argc; i++) { | 916 for (int i = 0; i < argc; i++) { |
| 959 Register arg = values[argc-1-i]; | 917 ASSERT(!receiver.is(values[i])); |
| 960 ASSERT(!receiver.is(arg)); | 918 ASSERT(!scratch.is(values[i])); |
| 961 ASSERT(!scratch.is(arg)); | 919 __ str(values[i], MemOperand(sp, index-- * kPointerSize)); |
| 962 __ push(arg); | |
| 963 } | 920 } |
| 964 Register scratch1 = r0; | 921 |
| 965 Register scratch2 = r1; | 922 GenerateFastApiDirectCall(masm, optimization, argc, true); |
| 966 Register scratch3 = r2; | |
| 967 if (!r3.is(receiver)) { | |
| 968 __ mov(r3, receiver); | |
| 969 receiver = r3; | |
| 970 } | |
| 971 // Stack now matches JSFunction abi. | |
| 972 GenerateFastApiCallBody(masm, | |
| 973 optimization, | |
| 974 argc, | |
| 975 receiver, | |
| 976 scratch1, | |
| 977 scratch2, | |
| 978 scratch3, | |
| 979 true); | |
| 980 } | 923 } |
| 981 | 924 |
| 982 | 925 |
| 983 class CallInterceptorCompiler BASE_EMBEDDED { | 926 class CallInterceptorCompiler BASE_EMBEDDED { |
| 984 public: | 927 public: |
| 985 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | 928 CallInterceptorCompiler(CallStubCompiler* stub_compiler, |
| 986 const ParameterCount& arguments, | 929 const ParameterCount& arguments, |
| 987 Register name) | 930 Register name) |
| 988 : stub_compiler_(stub_compiler), | 931 : stub_compiler_(stub_compiler), |
| 989 arguments_(arguments), | 932 arguments_(arguments), |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 Register scratch2, | 965 Register scratch2, |
| 1023 Register scratch3, | 966 Register scratch3, |
| 1024 Handle<JSObject> interceptor_holder, | 967 Handle<JSObject> interceptor_holder, |
| 1025 LookupResult* lookup, | 968 LookupResult* lookup, |
| 1026 Handle<Name> name, | 969 Handle<Name> name, |
| 1027 const CallOptimization& optimization, | 970 const CallOptimization& optimization, |
| 1028 Label* miss_label) { | 971 Label* miss_label) { |
| 1029 ASSERT(optimization.is_constant_call()); | 972 ASSERT(optimization.is_constant_call()); |
| 1030 ASSERT(!lookup->holder()->IsGlobalObject()); | 973 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 1031 Counters* counters = masm->isolate()->counters(); | 974 Counters* counters = masm->isolate()->counters(); |
| 975 int depth1 = kInvalidProtoDepth; |
| 976 int depth2 = kInvalidProtoDepth; |
| 977 bool can_do_fast_api_call = false; |
| 978 if (optimization.is_simple_api_call() && |
| 979 !lookup->holder()->IsGlobalObject()) { |
| 980 depth1 = optimization.GetPrototypeDepthOfExpectedType( |
| 981 object, interceptor_holder); |
| 982 if (depth1 == kInvalidProtoDepth) { |
| 983 depth2 = optimization.GetPrototypeDepthOfExpectedType( |
| 984 interceptor_holder, Handle<JSObject>(lookup->holder())); |
| 985 } |
| 986 can_do_fast_api_call = |
| 987 depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; |
| 988 } |
| 989 |
| 1032 __ IncrementCounter(counters->call_const_interceptor(), 1, | 990 __ IncrementCounter(counters->call_const_interceptor(), 1, |
| 1033 scratch1, scratch2); | 991 scratch1, scratch2); |
| 1034 | 992 |
| 993 if (can_do_fast_api_call) { |
| 994 __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, |
| 995 scratch1, scratch2); |
| 996 ReserveSpaceForFastApiCall(masm, scratch1); |
| 997 } |
| 998 |
| 1035 // Check that the maps from receiver to interceptor's holder | 999 // Check that the maps from receiver to interceptor's holder |
| 1036 // haven't changed and thus we can invoke interceptor. | 1000 // haven't changed and thus we can invoke interceptor. |
| 1037 Label miss_cleanup; | 1001 Label miss_cleanup; |
| 1002 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
| 1038 Register holder = | 1003 Register holder = |
| 1039 stub_compiler_->CheckPrototypes( | 1004 stub_compiler_->CheckPrototypes( |
| 1040 IC::CurrentTypeOf(object, masm->isolate()), receiver, | 1005 IC::CurrentTypeOf(object, masm->isolate()), receiver, |
| 1041 interceptor_holder, scratch1, scratch2, scratch3, | 1006 interceptor_holder, scratch1, scratch2, scratch3, |
| 1042 name, miss_label); | 1007 name, depth1, miss); |
| 1043 | 1008 |
| 1044 // Invoke an interceptor and if it provides a value, | 1009 // Invoke an interceptor and if it provides a value, |
| 1045 // branch to |regular_invoke|. | 1010 // branch to |regular_invoke|. |
| 1046 Label regular_invoke; | 1011 Label regular_invoke; |
| 1047 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, | 1012 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, |
| 1048 ®ular_invoke); | 1013 ®ular_invoke); |
| 1049 | 1014 |
| 1050 // Interceptor returned nothing for this property. Try to use cached | 1015 // Interceptor returned nothing for this property. Try to use cached |
| 1051 // constant function. | 1016 // constant function. |
| 1052 | 1017 |
| 1053 // Check that the maps from interceptor's holder to constant function's | 1018 // Check that the maps from interceptor's holder to constant function's |
| 1054 // holder haven't changed and thus we can use cached constant function. | 1019 // holder haven't changed and thus we can use cached constant function. |
| 1055 if (*interceptor_holder != lookup->holder()) { | 1020 if (*interceptor_holder != lookup->holder()) { |
| 1056 stub_compiler_->CheckPrototypes( | 1021 stub_compiler_->CheckPrototypes( |
| 1057 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | 1022 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, |
| 1058 handle(lookup->holder()), scratch1, scratch2, scratch3, | 1023 handle(lookup->holder()), scratch1, scratch2, scratch3, |
| 1059 name, miss_label); | 1024 name, depth2, miss); |
| 1060 } | 1025 } else { |
| 1061 | 1026 // CheckPrototypes has a side effect of fetching a 'holder' |
| 1062 Handle<Map> lookup_map; | 1027 // for API (object which is instanceof for the signature). It's |
| 1063 CallOptimization::HolderLookup holder_lookup = | 1028 // safe to omit it here, as if present, it should be fetched |
| 1064 CallOptimization::kHolderNotFound; | 1029 // by the previous CheckPrototypes. |
| 1065 if (optimization.is_simple_api_call() && | 1030 ASSERT(depth2 == kInvalidProtoDepth); |
| 1066 !lookup->holder()->IsGlobalObject()) { | |
| 1067 lookup_map = optimization.LookupHolderOfExpectedType( | |
| 1068 object, object, interceptor_holder, &holder_lookup); | |
| 1069 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 1070 lookup_map = | |
| 1071 optimization.LookupHolderOfExpectedType( | |
| 1072 object, | |
| 1073 interceptor_holder, | |
| 1074 Handle<JSObject>(lookup->holder()), | |
| 1075 &holder_lookup); | |
| 1076 } | |
| 1077 } | 1031 } |
| 1078 | 1032 |
| 1079 // Invoke function. | 1033 // Invoke function. |
| 1080 if (holder_lookup != CallOptimization::kHolderNotFound) { | 1034 if (can_do_fast_api_call) { |
| 1081 int argc = arguments_.immediate(); | 1035 GenerateFastApiDirectCall( |
| 1082 GenerateFastApiCall(masm, | 1036 masm, optimization, arguments_.immediate(), false); |
| 1083 optimization, | |
| 1084 argc, | |
| 1085 lookup_map, | |
| 1086 holder_lookup); | |
| 1087 } else { | 1037 } else { |
| 1088 Handle<JSFunction> function = optimization.constant_function(); | 1038 Handle<JSFunction> function = optimization.constant_function(); |
| 1089 __ Move(r0, receiver); | 1039 __ Move(r0, receiver); |
| 1090 stub_compiler_->GenerateJumpFunction(object, function); | 1040 stub_compiler_->GenerateJumpFunction(object, function); |
| 1091 } | 1041 } |
| 1092 | 1042 |
| 1043 // Deferred code for fast API call case---clean preallocated space. |
| 1044 if (can_do_fast_api_call) { |
| 1045 __ bind(&miss_cleanup); |
| 1046 FreeSpaceForFastApiCall(masm); |
| 1047 __ b(miss_label); |
| 1048 } |
| 1049 |
| 1093 // Invoke a regular function. | 1050 // Invoke a regular function. |
| 1094 __ bind(®ular_invoke); | 1051 __ bind(®ular_invoke); |
| 1052 if (can_do_fast_api_call) { |
| 1053 FreeSpaceForFastApiCall(masm); |
| 1054 } |
| 1095 } | 1055 } |
| 1096 | 1056 |
| 1097 void CompileRegular(MacroAssembler* masm, | 1057 void CompileRegular(MacroAssembler* masm, |
| 1098 Handle<JSObject> object, | 1058 Handle<JSObject> object, |
| 1099 Register receiver, | 1059 Register receiver, |
| 1100 Register scratch1, | 1060 Register scratch1, |
| 1101 Register scratch2, | 1061 Register scratch2, |
| 1102 Register scratch3, | 1062 Register scratch3, |
| 1103 Handle<Name> name, | 1063 Handle<Name> name, |
| 1104 Handle<JSObject> interceptor_holder, | 1064 Handle<JSObject> interceptor_holder, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 #define __ ACCESS_MASM(masm()) | 1120 #define __ ACCESS_MASM(masm()) |
| 1161 | 1121 |
| 1162 | 1122 |
| 1163 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, | 1123 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
| 1164 Register object_reg, | 1124 Register object_reg, |
| 1165 Handle<JSObject> holder, | 1125 Handle<JSObject> holder, |
| 1166 Register holder_reg, | 1126 Register holder_reg, |
| 1167 Register scratch1, | 1127 Register scratch1, |
| 1168 Register scratch2, | 1128 Register scratch2, |
| 1169 Handle<Name> name, | 1129 Handle<Name> name, |
| 1130 int save_at_depth, |
| 1170 Label* miss, | 1131 Label* miss, |
| 1171 PrototypeCheckType check) { | 1132 PrototypeCheckType check) { |
| 1172 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); | 1133 Handle<Map> receiver_map(IC::TypeToMap(*type, isolate())); |
| 1173 // Make sure that the type feedback oracle harvests the receiver map. | 1134 // Make sure that the type feedback oracle harvests the receiver map. |
| 1174 // TODO(svenpanne) Remove this hack when all ICs are reworked. | 1135 // TODO(svenpanne) Remove this hack when all ICs are reworked. |
| 1175 __ mov(scratch1, Operand(receiver_map)); | 1136 __ mov(scratch1, Operand(receiver_map)); |
| 1176 | 1137 |
| 1177 // Make sure there's no overlap between holder and object registers. | 1138 // Make sure there's no overlap between holder and object registers. |
| 1178 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 1139 ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
| 1179 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) | 1140 ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg) |
| 1180 && !scratch2.is(scratch1)); | 1141 && !scratch2.is(scratch1)); |
| 1181 | 1142 |
| 1182 // Keep track of the current object in register reg. | 1143 // Keep track of the current object in register reg. |
| 1183 Register reg = object_reg; | 1144 Register reg = object_reg; |
| 1184 int depth = 0; | 1145 int depth = 0; |
| 1185 | 1146 |
| 1147 typedef FunctionCallbackArguments FCA; |
| 1148 if (save_at_depth == depth) { |
| 1149 __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); |
| 1150 } |
| 1151 |
| 1186 Handle<JSObject> current = Handle<JSObject>::null(); | 1152 Handle<JSObject> current = Handle<JSObject>::null(); |
| 1187 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); | 1153 if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant()); |
| 1188 Handle<JSObject> prototype = Handle<JSObject>::null(); | 1154 Handle<JSObject> prototype = Handle<JSObject>::null(); |
| 1189 Handle<Map> current_map = receiver_map; | 1155 Handle<Map> current_map = receiver_map; |
| 1190 Handle<Map> holder_map(holder->map()); | 1156 Handle<Map> holder_map(holder->map()); |
| 1191 // Traverse the prototype chain and check the maps in the prototype chain for | 1157 // Traverse the prototype chain and check the maps in the prototype chain for |
| 1192 // fast and global objects or do negative lookup for normal objects. | 1158 // fast and global objects or do negative lookup for normal objects. |
| 1193 while (!current_map.is_identical_to(holder_map)) { | 1159 while (!current_map.is_identical_to(holder_map)) { |
| 1194 ++depth; | 1160 ++depth; |
| 1195 | 1161 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1241 if (heap()->InNewSpace(*prototype)) { | 1207 if (heap()->InNewSpace(*prototype)) { |
| 1242 // The prototype is in new space; we cannot store a reference to it | 1208 // The prototype is in new space; we cannot store a reference to it |
| 1243 // in the code. Load it from the map. | 1209 // in the code. Load it from the map. |
| 1244 __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); | 1210 __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset)); |
| 1245 } else { | 1211 } else { |
| 1246 // The prototype is in old space; load it directly. | 1212 // The prototype is in old space; load it directly. |
| 1247 __ mov(reg, Operand(prototype)); | 1213 __ mov(reg, Operand(prototype)); |
| 1248 } | 1214 } |
| 1249 } | 1215 } |
| 1250 | 1216 |
| 1217 if (save_at_depth == depth) { |
| 1218 __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); |
| 1219 } |
| 1220 |
| 1251 // Go to the next object in the prototype chain. | 1221 // Go to the next object in the prototype chain. |
| 1252 current = prototype; | 1222 current = prototype; |
| 1253 current_map = handle(current->map()); | 1223 current_map = handle(current->map()); |
| 1254 } | 1224 } |
| 1255 | 1225 |
| 1256 // Log the check depth. | 1226 // Log the check depth. |
| 1257 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 1227 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1258 | 1228 |
| 1259 if (depth != 0 || check == CHECK_ALL_MAPS) { | 1229 if (depth != 0 || check == CHECK_ALL_MAPS) { |
| 1260 // Check the holder map. | 1230 // Check the holder map. |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1609 Handle<JSFunction> function, | 1579 Handle<JSFunction> function, |
| 1610 Handle<String> name) { | 1580 Handle<String> name) { |
| 1611 Counters* counters = isolate()->counters(); | 1581 Counters* counters = isolate()->counters(); |
| 1612 | 1582 |
| 1613 ASSERT(optimization.is_simple_api_call()); | 1583 ASSERT(optimization.is_simple_api_call()); |
| 1614 // Bail out if object is a global object as we don't want to | 1584 // Bail out if object is a global object as we don't want to |
| 1615 // repatch it to global receiver. | 1585 // repatch it to global receiver. |
| 1616 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1586 if (object->IsGlobalObject()) return Handle<Code>::null(); |
| 1617 if (!cell.is_null()) return Handle<Code>::null(); | 1587 if (!cell.is_null()) return Handle<Code>::null(); |
| 1618 if (!object->IsJSObject()) return Handle<Code>::null(); | 1588 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 1619 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | 1589 int depth = optimization.GetPrototypeDepthOfExpectedType( |
| 1620 CallOptimization::HolderLookup holder_lookup = | 1590 Handle<JSObject>::cast(object), holder); |
| 1621 CallOptimization::kHolderNotFound; | 1591 if (depth == kInvalidProtoDepth) return Handle<Code>::null(); |
| 1622 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( | |
| 1623 receiver, receiver, holder, &holder_lookup); | |
| 1624 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 1625 return Handle<Code>::null(); | |
| 1626 } | |
| 1627 | 1592 |
| 1628 Label miss; | 1593 Label miss, miss_before_stack_reserved; |
| 1629 GenerateNameCheck(name, &miss); | 1594 GenerateNameCheck(name, &miss_before_stack_reserved); |
| 1630 | 1595 |
| 1631 // Get the receiver from the stack. | 1596 // Get the receiver from the stack. |
| 1632 const int argc = arguments().immediate(); | 1597 const int argc = arguments().immediate(); |
| 1633 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 1598 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
| 1634 | 1599 |
| 1635 // Check that the receiver isn't a smi. | 1600 // Check that the receiver isn't a smi. |
| 1636 __ JumpIfSmi(r1, &miss); | 1601 __ JumpIfSmi(r1, &miss_before_stack_reserved); |
| 1637 | 1602 |
| 1638 __ IncrementCounter(counters->call_const(), 1, r0, r3); | 1603 __ IncrementCounter(counters->call_const(), 1, r0, r3); |
| 1604 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3); |
| 1605 |
| 1606 ReserveSpaceForFastApiCall(masm(), r0); |
| 1639 | 1607 |
| 1640 // Check that the maps haven't changed and find a Holder as a side effect. | 1608 // Check that the maps haven't changed and find a Holder as a side effect. |
| 1641 CheckPrototypes( | 1609 CheckPrototypes( |
| 1642 IC::CurrentTypeOf(object, isolate()), | 1610 IC::CurrentTypeOf(object, isolate()), |
| 1643 r1, holder, r0, r3, r4, name, &miss); | 1611 r1, holder, r0, r3, r4, name, depth, &miss); |
| 1644 | 1612 |
| 1645 GenerateFastApiCall( | 1613 GenerateFastApiDirectCall(masm(), optimization, argc, false); |
| 1646 masm(), optimization, argc, lookup_map, holder_lookup); | |
| 1647 | 1614 |
| 1648 HandlerFrontendFooter(&miss); | 1615 __ bind(&miss); |
| 1616 FreeSpaceForFastApiCall(masm()); |
| 1617 |
| 1618 HandlerFrontendFooter(&miss_before_stack_reserved); |
| 1649 | 1619 |
| 1650 // Return the generated code. | 1620 // Return the generated code. |
| 1651 return GetCode(function); | 1621 return GetCode(function); |
| 1652 } | 1622 } |
| 1653 | 1623 |
| 1654 | 1624 |
| 1655 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1625 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 1656 Label success; | 1626 Label success; |
| 1657 // Check that the object is a boolean. | 1627 // Check that the object is a boolean. |
| 1658 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1628 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| (...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2201 // ----------------------------------- | 2171 // ----------------------------------- |
| 2202 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2172 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2203 } | 2173 } |
| 2204 | 2174 |
| 2205 | 2175 |
| 2206 #undef __ | 2176 #undef __ |
| 2207 | 2177 |
| 2208 } } // namespace v8::internal | 2178 } } // namespace v8::internal |
| 2209 | 2179 |
| 2210 #endif // V8_TARGET_ARCH_ARM | 2180 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |