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