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 |