| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1113 | 1153 |
| 1114 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 1154 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1115 __ Jump(code, RelocInfo::CODE_TARGET); | 1155 __ Jump(code, RelocInfo::CODE_TARGET); |
| 1116 } | 1156 } |
| 1117 | 1157 |
| 1118 | 1158 |
| 1119 #undef __ | 1159 #undef __ |
| 1120 #define __ ACCESS_MASM(masm()) | 1160 #define __ ACCESS_MASM(masm()) |
| 1121 | 1161 |
| 1122 | 1162 |
| 1123 Register StubCompiler::CheckPrototypes(Handle<Type> 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 28 matching lines...) Expand all Loading... |
| 1259 Label success; | 1289 Label success; |
| 1260 __ b(&success); | 1290 __ b(&success); |
| 1261 GenerateRestoreName(masm(), miss, name); | 1291 GenerateRestoreName(masm(), miss, name); |
| 1262 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1292 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 1263 __ bind(&success); | 1293 __ bind(&success); |
| 1264 } | 1294 } |
| 1265 } | 1295 } |
| 1266 | 1296 |
| 1267 | 1297 |
| 1268 Register LoadStubCompiler::CallbackHandlerFrontend( | 1298 Register LoadStubCompiler::CallbackHandlerFrontend( |
| 1269 Handle<Type> type, | 1299 Handle<HeapType> type, |
| 1270 Register object_reg, | 1300 Register object_reg, |
| 1271 Handle<JSObject> holder, | 1301 Handle<JSObject> holder, |
| 1272 Handle<Name> name, | 1302 Handle<Name> name, |
| 1273 Handle<Object> callback) { | 1303 Handle<Object> callback) { |
| 1274 Label miss; | 1304 Label miss; |
| 1275 | 1305 |
| 1276 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); | 1306 Register reg = HandlerFrontendHeader(type, object_reg, holder, name, &miss); |
| 1277 | 1307 |
| 1278 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { | 1308 if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
| 1279 ASSERT(!reg.is(scratch2())); | 1309 ASSERT(!reg.is(scratch2())); |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1564 index.translate(holder), Representation::Tagged()); | 1594 index.translate(holder), Representation::Tagged()); |
| 1565 GenerateJumpFunction(object, r1, &miss); | 1595 GenerateJumpFunction(object, r1, &miss); |
| 1566 | 1596 |
| 1567 HandlerFrontendFooter(&miss); | 1597 HandlerFrontendFooter(&miss); |
| 1568 | 1598 |
| 1569 // Return the generated code. | 1599 // Return the generated code. |
| 1570 return GetCode(Code::FAST, name); | 1600 return GetCode(Code::FAST, name); |
| 1571 } | 1601 } |
| 1572 | 1602 |
| 1573 | 1603 |
| 1574 Handle<Code> CallStubCompiler::CompileArrayCodeCall( | |
| 1575 Handle<Object> object, | |
| 1576 Handle<JSObject> holder, | |
| 1577 Handle<Cell> cell, | |
| 1578 Handle<JSFunction> function, | |
| 1579 Handle<String> name, | |
| 1580 Code::StubType type) { | |
| 1581 Label miss; | |
| 1582 | |
| 1583 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1584 if (!cell.is_null()) { | |
| 1585 ASSERT(cell->value() == *function); | |
| 1586 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 1587 } | |
| 1588 | |
| 1589 Handle<AllocationSite> site = isolate()->factory()->NewAllocationSite(); | |
| 1590 site->SetElementsKind(GetInitialFastElementsKind()); | |
| 1591 Handle<Cell> site_feedback_cell = isolate()->factory()->NewCell(site); | |
| 1592 const int argc = arguments().immediate(); | |
| 1593 __ mov(r0, Operand(argc)); | |
| 1594 __ mov(r2, Operand(site_feedback_cell)); | |
| 1595 __ mov(r1, Operand(function)); | |
| 1596 | |
| 1597 ArrayConstructorStub stub(isolate()); | |
| 1598 __ TailCallStub(&stub); | |
| 1599 | |
| 1600 HandlerFrontendFooter(&miss); | |
| 1601 | |
| 1602 // Return the generated code. | |
| 1603 return GetCode(type, name); | |
| 1604 } | |
| 1605 | |
| 1606 | |
| 1607 Handle<Code> CallStubCompiler::CompileArrayPushCall( | |
| 1608 Handle<Object> object, | |
| 1609 Handle<JSObject> holder, | |
| 1610 Handle<Cell> cell, | |
| 1611 Handle<JSFunction> function, | |
| 1612 Handle<String> name, | |
| 1613 Code::StubType type) { | |
| 1614 // If object is not an array or is observed or sealed, bail out to regular | |
| 1615 // call. | |
| 1616 if (!object->IsJSArray() || | |
| 1617 !cell.is_null() || | |
| 1618 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1619 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1620 return Handle<Code>::null(); | |
| 1621 } | |
| 1622 | |
| 1623 Label miss; | |
| 1624 | |
| 1625 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1626 Register receiver = r0; | |
| 1627 Register scratch = r1; | |
| 1628 | |
| 1629 const int argc = arguments().immediate(); | |
| 1630 if (argc == 0) { | |
| 1631 // Nothing to do, just return the length. | |
| 1632 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1633 __ Drop(argc + 1); | |
| 1634 __ Ret(); | |
| 1635 } else { | |
| 1636 Label call_builtin; | |
| 1637 | |
| 1638 if (argc == 1) { // Otherwise fall through to call the builtin. | |
| 1639 Label attempt_to_grow_elements, with_write_barrier, check_double; | |
| 1640 | |
| 1641 Register elements = r6; | |
| 1642 Register end_elements = r5; | |
| 1643 // Get the elements array of the object. | |
| 1644 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | |
| 1645 | |
| 1646 // Check that the elements are in fast mode and writable. | |
| 1647 __ CheckMap(elements, | |
| 1648 scratch, | |
| 1649 Heap::kFixedArrayMapRootIndex, | |
| 1650 &check_double, | |
| 1651 DONT_DO_SMI_CHECK); | |
| 1652 | |
| 1653 // Get the array's length into scratch and calculate new length. | |
| 1654 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1655 __ add(scratch, scratch, Operand(Smi::FromInt(argc))); | |
| 1656 | |
| 1657 // Get the elements' length. | |
| 1658 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1659 | |
| 1660 // Check if we could survive without allocation. | |
| 1661 __ cmp(scratch, r4); | |
| 1662 __ b(gt, &attempt_to_grow_elements); | |
| 1663 | |
| 1664 // Check if value is a smi. | |
| 1665 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1666 __ JumpIfNotSmi(r4, &with_write_barrier); | |
| 1667 | |
| 1668 // Save new length. | |
| 1669 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1670 | |
| 1671 // Store the value. | |
| 1672 // We may need a register containing the address end_elements below, | |
| 1673 // so write back the value in end_elements. | |
| 1674 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch)); | |
| 1675 const int kEndElementsOffset = | |
| 1676 FixedArray::kHeaderSize - kHeapObjectTag - argc * kPointerSize; | |
| 1677 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); | |
| 1678 | |
| 1679 // Check for a smi. | |
| 1680 __ Drop(argc + 1); | |
| 1681 __ mov(r0, scratch); | |
| 1682 __ Ret(); | |
| 1683 | |
| 1684 __ bind(&check_double); | |
| 1685 | |
| 1686 // Check that the elements are in fast mode and writable. | |
| 1687 __ CheckMap(elements, | |
| 1688 scratch, | |
| 1689 Heap::kFixedDoubleArrayMapRootIndex, | |
| 1690 &call_builtin, | |
| 1691 DONT_DO_SMI_CHECK); | |
| 1692 | |
| 1693 // Get the array's length into scratch and calculate new length. | |
| 1694 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1695 __ add(scratch, scratch, Operand(Smi::FromInt(argc))); | |
| 1696 | |
| 1697 // Get the elements' length. | |
| 1698 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1699 | |
| 1700 // Check if we could survive without allocation. | |
| 1701 __ cmp(scratch, r4); | |
| 1702 __ b(gt, &call_builtin); | |
| 1703 | |
| 1704 __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1705 __ StoreNumberToDoubleElements(r4, scratch, elements, r5, d0, | |
| 1706 &call_builtin, argc * kDoubleSize); | |
| 1707 | |
| 1708 // Save new length. | |
| 1709 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1710 | |
| 1711 __ Drop(argc + 1); | |
| 1712 __ mov(r0, scratch); | |
| 1713 __ Ret(); | |
| 1714 | |
| 1715 __ bind(&with_write_barrier); | |
| 1716 | |
| 1717 __ ldr(r3, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 1718 | |
| 1719 if (FLAG_smi_only_arrays && !FLAG_trace_elements_transitions) { | |
| 1720 Label fast_object, not_fast_object; | |
| 1721 __ CheckFastObjectElements(r3, r9, ¬_fast_object); | |
| 1722 __ jmp(&fast_object); | |
| 1723 // In case of fast smi-only, convert to fast object, otherwise bail out. | |
| 1724 __ bind(¬_fast_object); | |
| 1725 __ CheckFastSmiElements(r3, r9, &call_builtin); | |
| 1726 | |
| 1727 __ ldr(r9, FieldMemOperand(r4, HeapObject::kMapOffset)); | |
| 1728 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | |
| 1729 __ cmp(r9, ip); | |
| 1730 __ b(eq, &call_builtin); | |
| 1731 // edx: receiver | |
| 1732 // r3: map | |
| 1733 Label try_holey_map; | |
| 1734 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, | |
| 1735 FAST_ELEMENTS, | |
| 1736 r3, | |
| 1737 r9, | |
| 1738 &try_holey_map); | |
| 1739 __ mov(r2, receiver); | |
| 1740 ElementsTransitionGenerator:: | |
| 1741 GenerateMapChangeElementsTransition(masm(), | |
| 1742 DONT_TRACK_ALLOCATION_SITE, | |
| 1743 NULL); | |
| 1744 __ jmp(&fast_object); | |
| 1745 | |
| 1746 __ bind(&try_holey_map); | |
| 1747 __ LoadTransitionedArrayMapConditional(FAST_HOLEY_SMI_ELEMENTS, | |
| 1748 FAST_HOLEY_ELEMENTS, | |
| 1749 r3, | |
| 1750 r9, | |
| 1751 &call_builtin); | |
| 1752 __ mov(r2, receiver); | |
| 1753 ElementsTransitionGenerator:: | |
| 1754 GenerateMapChangeElementsTransition(masm(), | |
| 1755 DONT_TRACK_ALLOCATION_SITE, | |
| 1756 NULL); | |
| 1757 __ bind(&fast_object); | |
| 1758 } else { | |
| 1759 __ CheckFastObjectElements(r3, r3, &call_builtin); | |
| 1760 } | |
| 1761 | |
| 1762 // Save new length. | |
| 1763 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1764 | |
| 1765 // Store the value. | |
| 1766 // We may need a register containing the address end_elements below, | |
| 1767 // so write back the value in end_elements. | |
| 1768 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch)); | |
| 1769 __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); | |
| 1770 | |
| 1771 __ RecordWrite(elements, | |
| 1772 end_elements, | |
| 1773 r4, | |
| 1774 kLRHasNotBeenSaved, | |
| 1775 kDontSaveFPRegs, | |
| 1776 EMIT_REMEMBERED_SET, | |
| 1777 OMIT_SMI_CHECK); | |
| 1778 __ Drop(argc + 1); | |
| 1779 __ mov(r0, scratch); | |
| 1780 __ Ret(); | |
| 1781 | |
| 1782 __ bind(&attempt_to_grow_elements); | |
| 1783 // scratch: array's length + 1. | |
| 1784 | |
| 1785 if (!FLAG_inline_new) { | |
| 1786 __ b(&call_builtin); | |
| 1787 } | |
| 1788 | |
| 1789 __ ldr(r2, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1790 // Growing elements that are SMI-only requires special handling in case | |
| 1791 // the new element is non-Smi. For now, delegate to the builtin. | |
| 1792 Label no_fast_elements_check; | |
| 1793 __ JumpIfSmi(r2, &no_fast_elements_check); | |
| 1794 __ ldr(r9, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
| 1795 __ CheckFastObjectElements(r9, r9, &call_builtin); | |
| 1796 __ bind(&no_fast_elements_check); | |
| 1797 | |
| 1798 ExternalReference new_space_allocation_top = | |
| 1799 ExternalReference::new_space_allocation_top_address(isolate()); | |
| 1800 ExternalReference new_space_allocation_limit = | |
| 1801 ExternalReference::new_space_allocation_limit_address(isolate()); | |
| 1802 | |
| 1803 const int kAllocationDelta = 4; | |
| 1804 // Load top and check if it is the end of elements. | |
| 1805 __ add(end_elements, elements, Operand::PointerOffsetFromSmiKey(scratch)); | |
| 1806 __ add(end_elements, end_elements, Operand(kEndElementsOffset)); | |
| 1807 __ mov(r4, Operand(new_space_allocation_top)); | |
| 1808 __ ldr(r3, MemOperand(r4)); | |
| 1809 __ cmp(end_elements, r3); | |
| 1810 __ b(ne, &call_builtin); | |
| 1811 | |
| 1812 __ mov(r9, Operand(new_space_allocation_limit)); | |
| 1813 __ ldr(r9, MemOperand(r9)); | |
| 1814 __ add(r3, r3, Operand(kAllocationDelta * kPointerSize)); | |
| 1815 __ cmp(r3, r9); | |
| 1816 __ b(hi, &call_builtin); | |
| 1817 | |
| 1818 // We fit and could grow elements. | |
| 1819 // Update new_space_allocation_top. | |
| 1820 __ str(r3, MemOperand(r4)); | |
| 1821 // Push the argument. | |
| 1822 __ str(r2, MemOperand(end_elements)); | |
| 1823 // Fill the rest with holes. | |
| 1824 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex); | |
| 1825 for (int i = 1; i < kAllocationDelta; i++) { | |
| 1826 __ str(r3, MemOperand(end_elements, i * kPointerSize)); | |
| 1827 } | |
| 1828 | |
| 1829 // Update elements' and array's sizes. | |
| 1830 __ str(scratch, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1831 __ ldr(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1832 __ add(r4, r4, Operand(Smi::FromInt(kAllocationDelta))); | |
| 1833 __ str(r4, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
| 1834 | |
| 1835 // Elements are in new space, so write barrier is not required. | |
| 1836 __ Drop(argc + 1); | |
| 1837 __ mov(r0, scratch); | |
| 1838 __ Ret(); | |
| 1839 } | |
| 1840 __ bind(&call_builtin); | |
| 1841 __ TailCallExternalReference( | |
| 1842 ExternalReference(Builtins::c_ArrayPush, isolate()), argc + 1, 1); | |
| 1843 } | |
| 1844 | |
| 1845 HandlerFrontendFooter(&miss); | |
| 1846 | |
| 1847 // Return the generated code. | |
| 1848 return GetCode(type, name); | |
| 1849 } | |
| 1850 | |
| 1851 | |
| 1852 Handle<Code> CallStubCompiler::CompileArrayPopCall( | |
| 1853 Handle<Object> object, | |
| 1854 Handle<JSObject> holder, | |
| 1855 Handle<Cell> cell, | |
| 1856 Handle<JSFunction> function, | |
| 1857 Handle<String> name, | |
| 1858 Code::StubType type) { | |
| 1859 // If object is not an array or is observed or sealed, bail out to regular | |
| 1860 // call. | |
| 1861 if (!object->IsJSArray() || | |
| 1862 !cell.is_null() || | |
| 1863 Handle<JSArray>::cast(object)->map()->is_observed() || | |
| 1864 !Handle<JSArray>::cast(object)->map()->is_extensible()) { | |
| 1865 return Handle<Code>::null(); | |
| 1866 } | |
| 1867 | |
| 1868 Label miss, return_undefined, call_builtin; | |
| 1869 Register receiver = r0; | |
| 1870 Register scratch = r1; | |
| 1871 Register elements = r3; | |
| 1872 | |
| 1873 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1874 | |
| 1875 // Get the elements array of the object. | |
| 1876 __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset)); | |
| 1877 | |
| 1878 // Check that the elements are in fast mode and writable. | |
| 1879 __ CheckMap(elements, | |
| 1880 scratch, | |
| 1881 Heap::kFixedArrayMapRootIndex, | |
| 1882 &call_builtin, | |
| 1883 DONT_DO_SMI_CHECK); | |
| 1884 | |
| 1885 // Get the array's length into r4 and calculate new length. | |
| 1886 __ ldr(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1887 __ sub(r4, r4, Operand(Smi::FromInt(1)), SetCC); | |
| 1888 __ b(lt, &return_undefined); | |
| 1889 | |
| 1890 // Get the last element. | |
| 1891 __ LoadRoot(r6, Heap::kTheHoleValueRootIndex); | |
| 1892 // We can't address the last element in one operation. Compute the more | |
| 1893 // expensive shift first, and use an offset later on. | |
| 1894 __ add(elements, elements, Operand::PointerOffsetFromSmiKey(r4)); | |
| 1895 __ ldr(scratch, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
| 1896 __ cmp(scratch, r6); | |
| 1897 __ b(eq, &call_builtin); | |
| 1898 | |
| 1899 // Set the array's length. | |
| 1900 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset)); | |
| 1901 | |
| 1902 // Fill with the hole. | |
| 1903 __ str(r6, FieldMemOperand(elements, FixedArray::kHeaderSize)); | |
| 1904 const int argc = arguments().immediate(); | |
| 1905 __ Drop(argc + 1); | |
| 1906 __ mov(r0, scratch); | |
| 1907 __ Ret(); | |
| 1908 | |
| 1909 __ bind(&return_undefined); | |
| 1910 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | |
| 1911 __ Drop(argc + 1); | |
| 1912 __ Ret(); | |
| 1913 | |
| 1914 __ bind(&call_builtin); | |
| 1915 __ TailCallExternalReference( | |
| 1916 ExternalReference(Builtins::c_ArrayPop, isolate()), argc + 1, 1); | |
| 1917 | |
| 1918 HandlerFrontendFooter(&miss); | |
| 1919 | |
| 1920 // Return the generated code. | |
| 1921 return GetCode(type, name); | |
| 1922 } | |
| 1923 | |
| 1924 | |
| 1925 Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( | |
| 1926 Handle<Object> object, | |
| 1927 Handle<JSObject> holder, | |
| 1928 Handle<Cell> cell, | |
| 1929 Handle<JSFunction> function, | |
| 1930 Handle<String> name, | |
| 1931 Code::StubType type) { | |
| 1932 // If object is not a string, bail out to regular call. | |
| 1933 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null(); | |
| 1934 | |
| 1935 Label miss; | |
| 1936 Label name_miss; | |
| 1937 Label index_out_of_range; | |
| 1938 Label* index_out_of_range_label = &index_out_of_range; | |
| 1939 | |
| 1940 if (kind_ == Code::CALL_IC && | |
| 1941 (CallICBase::StringStubState::decode(extra_state()) == | |
| 1942 DEFAULT_STRING_STUB)) { | |
| 1943 index_out_of_range_label = &miss; | |
| 1944 } | |
| 1945 | |
| 1946 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); | |
| 1947 | |
| 1948 Register receiver = r0; | |
| 1949 Register index = r4; | |
| 1950 Register result = r1; | |
| 1951 const int argc = arguments().immediate(); | |
| 1952 __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); | |
| 1953 if (argc > 0) { | |
| 1954 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 1955 } else { | |
| 1956 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); | |
| 1957 } | |
| 1958 | |
| 1959 StringCharCodeAtGenerator generator(receiver, | |
| 1960 index, | |
| 1961 result, | |
| 1962 &miss, // When not a string. | |
| 1963 &miss, // When not a number. | |
| 1964 index_out_of_range_label, | |
| 1965 STRING_INDEX_IS_NUMBER); | |
| 1966 generator.GenerateFast(masm()); | |
| 1967 __ Drop(argc + 1); | |
| 1968 __ mov(r0, result); | |
| 1969 __ Ret(); | |
| 1970 | |
| 1971 StubRuntimeCallHelper call_helper; | |
| 1972 generator.GenerateSlow(masm(), call_helper); | |
| 1973 | |
| 1974 if (index_out_of_range.is_linked()) { | |
| 1975 __ bind(&index_out_of_range); | |
| 1976 __ LoadRoot(r0, Heap::kNanValueRootIndex); | |
| 1977 __ Drop(argc + 1); | |
| 1978 __ Ret(); | |
| 1979 } | |
| 1980 | |
| 1981 __ bind(&miss); | |
| 1982 // Restore function name in r2. | |
| 1983 __ Move(r2, name); | |
| 1984 HandlerFrontendFooter(&name_miss); | |
| 1985 | |
| 1986 // Return the generated code. | |
| 1987 return GetCode(type, name); | |
| 1988 } | |
| 1989 | |
| 1990 | |
| 1991 Handle<Code> CallStubCompiler::CompileStringCharAtCall( | |
| 1992 Handle<Object> object, | |
| 1993 Handle<JSObject> holder, | |
| 1994 Handle<Cell> cell, | |
| 1995 Handle<JSFunction> function, | |
| 1996 Handle<String> name, | |
| 1997 Code::StubType type) { | |
| 1998 // If object is not a string, bail out to regular call. | |
| 1999 if (!object->IsString() || !cell.is_null()) return Handle<Code>::null(); | |
| 2000 | |
| 2001 const int argc = arguments().immediate(); | |
| 2002 Label miss; | |
| 2003 Label name_miss; | |
| 2004 Label index_out_of_range; | |
| 2005 Label* index_out_of_range_label = &index_out_of_range; | |
| 2006 if (kind_ == Code::CALL_IC && | |
| 2007 (CallICBase::StringStubState::decode(extra_state()) == | |
| 2008 DEFAULT_STRING_STUB)) { | |
| 2009 index_out_of_range_label = &miss; | |
| 2010 } | |
| 2011 | |
| 2012 HandlerFrontendHeader(object, holder, name, STRING_CHECK, &name_miss); | |
| 2013 | |
| 2014 Register receiver = r0; | |
| 2015 Register index = r4; | |
| 2016 Register scratch = r3; | |
| 2017 Register result = r1; | |
| 2018 if (argc > 0) { | |
| 2019 __ ldr(index, MemOperand(sp, (argc - 1) * kPointerSize)); | |
| 2020 } else { | |
| 2021 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); | |
| 2022 } | |
| 2023 | |
| 2024 StringCharAtGenerator generator(receiver, | |
| 2025 index, | |
| 2026 scratch, | |
| 2027 result, | |
| 2028 &miss, // When not a string. | |
| 2029 &miss, // When not a number. | |
| 2030 index_out_of_range_label, | |
| 2031 STRING_INDEX_IS_NUMBER); | |
| 2032 generator.GenerateFast(masm()); | |
| 2033 __ Drop(argc + 1); | |
| 2034 __ mov(r0, result); | |
| 2035 __ Ret(); | |
| 2036 | |
| 2037 StubRuntimeCallHelper call_helper; | |
| 2038 generator.GenerateSlow(masm(), call_helper); | |
| 2039 | |
| 2040 if (index_out_of_range.is_linked()) { | |
| 2041 __ bind(&index_out_of_range); | |
| 2042 __ LoadRoot(r0, Heap::kempty_stringRootIndex); | |
| 2043 __ Drop(argc + 1); | |
| 2044 __ Ret(); | |
| 2045 } | |
| 2046 | |
| 2047 __ bind(&miss); | |
| 2048 // Restore function name in r2. | |
| 2049 __ Move(r2, name); | |
| 2050 HandlerFrontendFooter(&name_miss); | |
| 2051 | |
| 2052 // Return the generated code. | |
| 2053 return GetCode(type, name); | |
| 2054 } | |
| 2055 | |
| 2056 | |
| 2057 Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( | |
| 2058 Handle<Object> object, | |
| 2059 Handle<JSObject> holder, | |
| 2060 Handle<Cell> cell, | |
| 2061 Handle<JSFunction> function, | |
| 2062 Handle<String> name, | |
| 2063 Code::StubType type) { | |
| 2064 const int argc = arguments().immediate(); | |
| 2065 | |
| 2066 // If the object is not a JSObject or we got an unexpected number of | |
| 2067 // arguments, bail out to the regular call. | |
| 2068 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); | |
| 2069 | |
| 2070 Label miss; | |
| 2071 | |
| 2072 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2073 if (!cell.is_null()) { | |
| 2074 ASSERT(cell->value() == *function); | |
| 2075 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2076 } | |
| 2077 | |
| 2078 // Load the char code argument. | |
| 2079 Register code = r1; | |
| 2080 __ ldr(code, MemOperand(sp, 0 * kPointerSize)); | |
| 2081 | |
| 2082 // Check the code is a smi. | |
| 2083 Label slow; | |
| 2084 __ JumpIfNotSmi(code, &slow); | |
| 2085 | |
| 2086 // Convert the smi code to uint16. | |
| 2087 __ and_(code, code, Operand(Smi::FromInt(0xffff))); | |
| 2088 | |
| 2089 StringCharFromCodeGenerator generator(code, r0); | |
| 2090 generator.GenerateFast(masm()); | |
| 2091 __ Drop(argc + 1); | |
| 2092 __ Ret(); | |
| 2093 | |
| 2094 StubRuntimeCallHelper call_helper; | |
| 2095 generator.GenerateSlow(masm(), call_helper); | |
| 2096 | |
| 2097 __ bind(&slow); | |
| 2098 // We do not have to patch the receiver because the function makes no use of | |
| 2099 // it. | |
| 2100 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2101 | |
| 2102 HandlerFrontendFooter(&miss); | |
| 2103 | |
| 2104 // Return the generated code. | |
| 2105 return GetCode(type, name); | |
| 2106 } | |
| 2107 | |
| 2108 | |
| 2109 Handle<Code> CallStubCompiler::CompileMathFloorCall( | |
| 2110 Handle<Object> object, | |
| 2111 Handle<JSObject> holder, | |
| 2112 Handle<Cell> cell, | |
| 2113 Handle<JSFunction> function, | |
| 2114 Handle<String> name, | |
| 2115 Code::StubType type) { | |
| 2116 const int argc = arguments().immediate(); | |
| 2117 // If the object is not a JSObject or we got an unexpected number of | |
| 2118 // arguments, bail out to the regular call. | |
| 2119 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); | |
| 2120 | |
| 2121 Label miss, slow; | |
| 2122 | |
| 2123 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2124 if (!cell.is_null()) { | |
| 2125 ASSERT(cell->value() == *function); | |
| 2126 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2127 } | |
| 2128 | |
| 2129 // Load the (only) argument into r0. | |
| 2130 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); | |
| 2131 | |
| 2132 // If the argument is a smi, just return. | |
| 2133 __ SmiTst(r0); | |
| 2134 __ Drop(argc + 1, eq); | |
| 2135 __ Ret(eq); | |
| 2136 | |
| 2137 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); | |
| 2138 | |
| 2139 Label smi_check, just_return; | |
| 2140 | |
| 2141 // Load the HeapNumber value. | |
| 2142 // We will need access to the value in the core registers, so we load it | |
| 2143 // with ldrd and move it to the fpu. It also spares a sub instruction for | |
| 2144 // updating the HeapNumber value address, as vldr expects a multiple | |
| 2145 // of 4 offset. | |
| 2146 __ Ldrd(r4, r5, FieldMemOperand(r0, HeapNumber::kValueOffset)); | |
| 2147 __ vmov(d1, r4, r5); | |
| 2148 | |
| 2149 // Check for NaN, Infinities and -0. | |
| 2150 // They are invariant through a Math.Floor call, so just | |
| 2151 // return the original argument. | |
| 2152 __ Sbfx(r3, r5, HeapNumber::kExponentShift, HeapNumber::kExponentBits); | |
| 2153 __ cmp(r3, Operand(-1)); | |
| 2154 __ b(eq, &just_return); | |
| 2155 __ eor(r3, r5, Operand(0x80000000u)); | |
| 2156 __ orr(r3, r3, r4, SetCC); | |
| 2157 __ b(eq, &just_return); | |
| 2158 // Test for values that can be exactly represented as a | |
| 2159 // signed 32-bit integer. | |
| 2160 __ TryDoubleToInt32Exact(r0, d1, d2); | |
| 2161 // If exact, check smi | |
| 2162 __ b(eq, &smi_check); | |
| 2163 __ cmp(r5, Operand(0)); | |
| 2164 | |
| 2165 // If input is in ]+0, +inf[, the cmp has cleared overflow and negative | |
| 2166 // (V=0 and N=0), the two following instructions won't execute and | |
| 2167 // we fall through smi_check to check if the result can fit into a smi. | |
| 2168 | |
| 2169 // If input is in ]-inf, -0[, sub one and, go to slow if we have | |
| 2170 // an overflow. Else we fall through smi check. | |
| 2171 // Hint: if x is a negative, non integer number, | |
| 2172 // floor(x) <=> round_to_zero(x) - 1. | |
| 2173 __ sub(r0, r0, Operand(1), SetCC, mi); | |
| 2174 __ b(vs, &slow); | |
| 2175 | |
| 2176 __ bind(&smi_check); | |
| 2177 // Check if the result can fit into an smi. If we had an overflow, | |
| 2178 // the result is either 0x80000000 or 0x7FFFFFFF and won't fit into an smi. | |
| 2179 // If result doesn't fit into an smi, branch to slow. | |
| 2180 __ SmiTag(r0, SetCC); | |
| 2181 __ b(vs, &slow); | |
| 2182 | |
| 2183 __ bind(&just_return); | |
| 2184 __ Drop(argc + 1); | |
| 2185 __ Ret(); | |
| 2186 | |
| 2187 __ bind(&slow); | |
| 2188 // We do not have to patch the receiver because the function makes no use of | |
| 2189 // it. | |
| 2190 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2191 | |
| 2192 HandlerFrontendFooter(&miss); | |
| 2193 | |
| 2194 // Return the generated code. | |
| 2195 return GetCode(type, name); | |
| 2196 } | |
| 2197 | |
| 2198 | |
| 2199 Handle<Code> CallStubCompiler::CompileMathAbsCall( | |
| 2200 Handle<Object> object, | |
| 2201 Handle<JSObject> holder, | |
| 2202 Handle<Cell> cell, | |
| 2203 Handle<JSFunction> function, | |
| 2204 Handle<String> name, | |
| 2205 Code::StubType type) { | |
| 2206 const int argc = arguments().immediate(); | |
| 2207 // If the object is not a JSObject or we got an unexpected number of | |
| 2208 // arguments, bail out to the regular call. | |
| 2209 if (!object->IsJSObject() || argc != 1) return Handle<Code>::null(); | |
| 2210 | |
| 2211 Label miss; | |
| 2212 | |
| 2213 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 2214 if (!cell.is_null()) { | |
| 2215 ASSERT(cell->value() == *function); | |
| 2216 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 2217 } | |
| 2218 | |
| 2219 // Load the (only) argument into r0. | |
| 2220 __ ldr(r0, MemOperand(sp, 0 * kPointerSize)); | |
| 2221 | |
| 2222 // Check if the argument is a smi. | |
| 2223 Label not_smi; | |
| 2224 __ JumpIfNotSmi(r0, ¬_smi); | |
| 2225 | |
| 2226 // Do bitwise not or do nothing depending on the sign of the | |
| 2227 // argument. | |
| 2228 __ eor(r1, r0, Operand(r0, ASR, kBitsPerInt - 1)); | |
| 2229 | |
| 2230 // Add 1 or do nothing depending on the sign of the argument. | |
| 2231 __ sub(r0, r1, Operand(r0, ASR, kBitsPerInt - 1), SetCC); | |
| 2232 | |
| 2233 // If the result is still negative, go to the slow case. | |
| 2234 // This only happens for the most negative smi. | |
| 2235 Label slow; | |
| 2236 __ b(mi, &slow); | |
| 2237 | |
| 2238 // Smi case done. | |
| 2239 __ Drop(argc + 1); | |
| 2240 __ Ret(); | |
| 2241 | |
| 2242 // Check if the argument is a heap number and load its exponent and | |
| 2243 // sign. | |
| 2244 __ bind(¬_smi); | |
| 2245 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, &slow, DONT_DO_SMI_CHECK); | |
| 2246 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | |
| 2247 | |
| 2248 // Check the sign of the argument. If the argument is positive, | |
| 2249 // just return it. | |
| 2250 Label negative_sign; | |
| 2251 __ tst(r1, Operand(HeapNumber::kSignMask)); | |
| 2252 __ b(ne, &negative_sign); | |
| 2253 __ Drop(argc + 1); | |
| 2254 __ Ret(); | |
| 2255 | |
| 2256 // If the argument is negative, clear the sign, and return a new | |
| 2257 // number. | |
| 2258 __ bind(&negative_sign); | |
| 2259 __ eor(r1, r1, Operand(HeapNumber::kSignMask)); | |
| 2260 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); | |
| 2261 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex); | |
| 2262 __ AllocateHeapNumber(r0, r4, r5, r6, &slow); | |
| 2263 __ str(r1, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | |
| 2264 __ str(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); | |
| 2265 __ Drop(argc + 1); | |
| 2266 __ Ret(); | |
| 2267 | |
| 2268 __ bind(&slow); | |
| 2269 // We do not have to patch the receiver because the function makes no use of | |
| 2270 // it. | |
| 2271 GenerateJumpFunctionIgnoreReceiver(function); | |
| 2272 | |
| 2273 HandlerFrontendFooter(&miss); | |
| 2274 | |
| 2275 // Return the generated code. | |
| 2276 return GetCode(type, name); | |
| 2277 } | |
| 2278 | |
| 2279 | |
| 2280 Handle<Code> CallStubCompiler::CompileFastApiCall( | 1604 Handle<Code> CallStubCompiler::CompileFastApiCall( |
| 2281 const CallOptimization& optimization, | 1605 const CallOptimization& optimization, |
| 2282 Handle<Object> object, | 1606 Handle<Object> object, |
| 2283 Handle<JSObject> holder, | 1607 Handle<JSObject> holder, |
| 2284 Handle<Cell> cell, | 1608 Handle<Cell> cell, |
| 2285 Handle<JSFunction> function, | 1609 Handle<JSFunction> function, |
| 2286 Handle<String> name) { | 1610 Handle<String> name) { |
| 2287 Counters* counters = isolate()->counters(); | 1611 Counters* counters = isolate()->counters(); |
| 2288 | 1612 |
| 2289 ASSERT(optimization.is_simple_api_call()); | 1613 ASSERT(optimization.is_simple_api_call()); |
| 2290 // 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 |
| 2291 // repatch it to global receiver. | 1615 // repatch it to global receiver. |
| 2292 if (object->IsGlobalObject()) return Handle<Code>::null(); | 1616 if (object->IsGlobalObject()) return Handle<Code>::null(); |
| 2293 if (!cell.is_null()) return Handle<Code>::null(); | 1617 if (!cell.is_null()) return Handle<Code>::null(); |
| 2294 if (!object->IsJSObject()) return Handle<Code>::null(); | 1618 if (!object->IsJSObject()) return Handle<Code>::null(); |
| 2295 int depth = optimization.GetPrototypeDepthOfExpectedType( | 1619 Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| 2296 Handle<JSObject>::cast(object), holder); | 1620 CallOptimization::HolderLookup holder_lookup = |
| 2297 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 } |
| 2298 | 1627 |
| 2299 Label miss, miss_before_stack_reserved; | 1628 Label miss; |
| 2300 GenerateNameCheck(name, &miss_before_stack_reserved); | 1629 GenerateNameCheck(name, &miss); |
| 2301 | 1630 |
| 2302 // Get the receiver from the stack. | 1631 // Get the receiver from the stack. |
| 2303 const int argc = arguments().immediate(); | 1632 const int argc = arguments().immediate(); |
| 2304 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | 1633 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); |
| 2305 | 1634 |
| 2306 // Check that the receiver isn't a smi. | 1635 // Check that the receiver isn't a smi. |
| 2307 __ JumpIfSmi(r1, &miss_before_stack_reserved); | 1636 __ JumpIfSmi(r1, &miss); |
| 2308 | 1637 |
| 2309 __ IncrementCounter(counters->call_const(), 1, r0, r3); | 1638 __ IncrementCounter(counters->call_const(), 1, r0, r3); |
| 2310 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3); | |
| 2311 | |
| 2312 ReserveSpaceForFastApiCall(masm(), r0); | |
| 2313 | 1639 |
| 2314 // 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. |
| 2315 CheckPrototypes( | 1641 CheckPrototypes( |
| 2316 IC::CurrentTypeOf(object, isolate()), | 1642 IC::CurrentTypeOf(object, isolate()), |
| 2317 r1, holder, r0, r3, r4, name, depth, &miss); | 1643 r1, holder, r0, r3, r4, name, &miss); |
| 2318 | 1644 |
| 2319 GenerateFastApiDirectCall(masm(), optimization, argc, false); | 1645 GenerateFastApiCall( |
| 1646 masm(), optimization, argc, lookup_map, holder_lookup); |
| 2320 | 1647 |
| 2321 __ bind(&miss); | 1648 HandlerFrontendFooter(&miss); |
| 2322 FreeSpaceForFastApiCall(masm()); | |
| 2323 | |
| 2324 HandlerFrontendFooter(&miss_before_stack_reserved); | |
| 2325 | 1649 |
| 2326 // Return the generated code. | 1650 // Return the generated code. |
| 2327 return GetCode(function); | 1651 return GetCode(function); |
| 2328 } | 1652 } |
| 2329 | 1653 |
| 2330 | 1654 |
| 2331 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1655 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 2332 Label success; | 1656 Label success; |
| 2333 // Check that the object is a boolean. | 1657 // Check that the object is a boolean. |
| 2334 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1658 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2511 // Return the generated code. | 1835 // Return the generated code. |
| 2512 return GetCode(Code::NORMAL, name); | 1836 return GetCode(Code::NORMAL, name); |
| 2513 } | 1837 } |
| 2514 | 1838 |
| 2515 | 1839 |
| 2516 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1840 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2517 Handle<JSObject> object, | 1841 Handle<JSObject> object, |
| 2518 Handle<JSObject> holder, | 1842 Handle<JSObject> holder, |
| 2519 Handle<Name> name, | 1843 Handle<Name> name, |
| 2520 Handle<ExecutableAccessorInfo> callback) { | 1844 Handle<ExecutableAccessorInfo> callback) { |
| 2521 HandlerFrontend(IC::CurrentTypeOf(object, isolate()), | 1845 Register holder_reg = HandlerFrontend( |
| 2522 receiver(), holder, name); | 1846 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 2523 | 1847 |
| 2524 // Stub never generated for non-global objects that require access checks. | 1848 // Stub never generated for non-global objects that require access checks. |
| 2525 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 1849 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| 2526 | 1850 |
| 2527 __ push(receiver()); // receiver | 1851 __ push(receiver()); // receiver |
| 1852 __ push(holder_reg); |
| 2528 __ mov(ip, Operand(callback)); // callback info | 1853 __ mov(ip, Operand(callback)); // callback info |
| 2529 __ push(ip); | 1854 __ push(ip); |
| 2530 __ mov(ip, Operand(name)); | 1855 __ mov(ip, Operand(name)); |
| 2531 __ Push(ip, value()); | 1856 __ Push(ip, value()); |
| 2532 | 1857 |
| 2533 // Do tail-call to the runtime system. | 1858 // Do tail-call to the runtime system. |
| 2534 ExternalReference store_callback_property = | 1859 ExternalReference store_callback_property = |
| 2535 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); | 1860 ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate()); |
| 2536 __ TailCallExternalReference(store_callback_property, 4, 1); | 1861 __ TailCallExternalReference(store_callback_property, 5, 1); |
| 2537 | 1862 |
| 2538 // Return the generated code. | 1863 // Return the generated code. |
| 2539 return GetCode(kind(), Code::FAST, name); | 1864 return GetCode(kind(), Code::FAST, name); |
| 2540 } | 1865 } |
| 2541 | 1866 |
| 2542 | 1867 |
| 2543 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1868 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 2544 Handle<JSObject> object, | 1869 Handle<JSObject> object, |
| 2545 Handle<JSObject> holder, | 1870 Handle<JSObject> holder, |
| 2546 Handle<Name> name, | 1871 Handle<Name> name, |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2630 | 1955 |
| 2631 // Handle store cache miss. | 1956 // Handle store cache miss. |
| 2632 __ bind(&miss); | 1957 __ bind(&miss); |
| 2633 TailCallBuiltin(masm(), MissBuiltin(kind())); | 1958 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 2634 | 1959 |
| 2635 // Return the generated code. | 1960 // Return the generated code. |
| 2636 return GetCode(kind(), Code::FAST, name); | 1961 return GetCode(kind(), Code::FAST, name); |
| 2637 } | 1962 } |
| 2638 | 1963 |
| 2639 | 1964 |
| 2640 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<Type> type, | 1965 Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<HeapType> type, |
| 2641 Handle<JSObject> last, | 1966 Handle<JSObject> last, |
| 2642 Handle<Name> name) { | 1967 Handle<Name> name) { |
| 2643 NonexistentHandlerFrontend(type, last, name); | 1968 NonexistentHandlerFrontend(type, last, name); |
| 2644 | 1969 |
| 2645 // Return undefined if maps of the full prototype chain are still the | 1970 // Return undefined if maps of the full prototype chain are still the |
| 2646 // same and no global property with this name contains a value. | 1971 // same and no global property with this name contains a value. |
| 2647 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 1972 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 2648 __ Ret(); | 1973 __ Ret(); |
| 2649 | 1974 |
| 2650 // Return the generated code. | 1975 // Return the generated code. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2673 } | 1998 } |
| 2674 | 1999 |
| 2675 | 2000 |
| 2676 Register* KeyedStoreStubCompiler::registers() { | 2001 Register* KeyedStoreStubCompiler::registers() { |
| 2677 // receiver, name, value, scratch1, scratch2, scratch3. | 2002 // receiver, name, value, scratch1, scratch2, scratch3. |
| 2678 static Register registers[] = { r2, r1, r0, r3, r4, r5 }; | 2003 static Register registers[] = { r2, r1, r0, r3, r4, r5 }; |
| 2679 return registers; | 2004 return registers; |
| 2680 } | 2005 } |
| 2681 | 2006 |
| 2682 | 2007 |
| 2683 void KeyedLoadStubCompiler::GenerateNameCheck(Handle<Name> name, | |
| 2684 Register name_reg, | |
| 2685 Label* miss) { | |
| 2686 __ cmp(name_reg, Operand(name)); | |
| 2687 __ b(ne, miss); | |
| 2688 } | |
| 2689 | |
| 2690 | |
| 2691 void KeyedStoreStubCompiler::GenerateNameCheck(Handle<Name> name, | |
| 2692 Register name_reg, | |
| 2693 Label* miss) { | |
| 2694 __ cmp(name_reg, Operand(name)); | |
| 2695 __ b(ne, miss); | |
| 2696 } | |
| 2697 | |
| 2698 | |
| 2699 #undef __ | 2008 #undef __ |
| 2700 #define __ ACCESS_MASM(masm) | 2009 #define __ ACCESS_MASM(masm) |
| 2701 | 2010 |
| 2702 | 2011 |
| 2703 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, | 2012 void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm, |
| 2704 Register receiver, | 2013 Register receiver, |
| 2705 Handle<JSFunction> getter) { | 2014 Handle<JSFunction> getter) { |
| 2706 // ----------- S t a t e ------------- | 2015 // ----------- S t a t e ------------- |
| 2707 // -- r0 : receiver | 2016 // -- r0 : receiver |
| 2708 // -- r2 : name | 2017 // -- r2 : name |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2729 } | 2038 } |
| 2730 __ Ret(); | 2039 __ Ret(); |
| 2731 } | 2040 } |
| 2732 | 2041 |
| 2733 | 2042 |
| 2734 #undef __ | 2043 #undef __ |
| 2735 #define __ ACCESS_MASM(masm()) | 2044 #define __ ACCESS_MASM(masm()) |
| 2736 | 2045 |
| 2737 | 2046 |
| 2738 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 2047 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 2739 Handle<Type> type, | 2048 Handle<HeapType> type, |
| 2740 Handle<GlobalObject> global, | 2049 Handle<GlobalObject> global, |
| 2741 Handle<PropertyCell> cell, | 2050 Handle<PropertyCell> cell, |
| 2742 Handle<Name> name, | 2051 Handle<Name> name, |
| 2743 bool is_dont_delete) { | 2052 bool is_dont_delete) { |
| 2744 Label miss; | 2053 Label miss; |
| 2745 | 2054 |
| 2746 HandlerFrontendHeader(type, receiver(), global, name, &miss); | 2055 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 2747 | 2056 |
| 2748 // Get the value from the cell. | 2057 // Get the value from the cell. |
| 2749 __ mov(r3, Operand(cell)); | 2058 __ mov(r3, Operand(cell)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2769 | 2078 |
| 2770 | 2079 |
| 2771 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 2080 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2772 TypeHandleList* types, | 2081 TypeHandleList* types, |
| 2773 CodeHandleList* handlers, | 2082 CodeHandleList* handlers, |
| 2774 Handle<Name> name, | 2083 Handle<Name> name, |
| 2775 Code::StubType type, | 2084 Code::StubType type, |
| 2776 IcCheckType check) { | 2085 IcCheckType check) { |
| 2777 Label miss; | 2086 Label miss; |
| 2778 | 2087 |
| 2779 if (check == PROPERTY) { | 2088 if (check == PROPERTY && |
| 2780 GenerateNameCheck(name, this->name(), &miss); | 2089 (kind() == Code::KEYED_LOAD_IC || kind() == Code::KEYED_STORE_IC)) { |
| 2090 __ cmp(this->name(), Operand(name)); |
| 2091 __ b(ne, &miss); |
| 2781 } | 2092 } |
| 2782 | 2093 |
| 2783 Label number_case; | 2094 Label number_case; |
| 2784 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; | 2095 Label* smi_target = IncludesNumberType(types) ? &number_case : &miss; |
| 2785 __ JumpIfSmi(receiver(), smi_target); | 2096 __ JumpIfSmi(receiver(), smi_target); |
| 2786 | 2097 |
| 2787 Register map_reg = scratch1(); | 2098 Register map_reg = scratch1(); |
| 2788 | 2099 |
| 2789 int receiver_count = types->length(); | 2100 int receiver_count = types->length(); |
| 2790 int number_of_handled_maps = 0; | 2101 int number_of_handled_maps = 0; |
| 2791 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); | 2102 __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset)); |
| 2792 for (int current = 0; current < receiver_count; ++current) { | 2103 for (int current = 0; current < receiver_count; ++current) { |
| 2793 Handle<Type> type = types->at(current); | 2104 Handle<HeapType> type = types->at(current); |
| 2794 Handle<Map> map = IC::TypeToMap(*type, isolate()); | 2105 Handle<Map> map = IC::TypeToMap(*type, isolate()); |
| 2795 if (!map->is_deprecated()) { | 2106 if (!map->is_deprecated()) { |
| 2796 number_of_handled_maps++; | 2107 number_of_handled_maps++; |
| 2797 __ mov(ip, Operand(map)); | 2108 __ mov(ip, Operand(map)); |
| 2798 __ cmp(map_reg, ip); | 2109 __ cmp(map_reg, ip); |
| 2799 if (type->Is(Type::Number())) { | 2110 if (type->Is(HeapType::Number())) { |
| 2800 ASSERT(!number_case.is_unused()); | 2111 ASSERT(!number_case.is_unused()); |
| 2801 __ bind(&number_case); | 2112 __ bind(&number_case); |
| 2802 } | 2113 } |
| 2803 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); | 2114 __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq); |
| 2804 } | 2115 } |
| 2805 } | 2116 } |
| 2806 ASSERT(number_of_handled_maps != 0); | 2117 ASSERT(number_of_handled_maps != 0); |
| 2807 | 2118 |
| 2808 __ bind(&miss); | 2119 __ bind(&miss); |
| 2809 TailCallBuiltin(masm(), MissBuiltin(kind())); | 2120 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2890 // ----------------------------------- | 2201 // ----------------------------------- |
| 2891 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 2202 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2892 } | 2203 } |
| 2893 | 2204 |
| 2894 | 2205 |
| 2895 #undef __ | 2206 #undef __ |
| 2896 | 2207 |
| 2897 } } // namespace v8::internal | 2208 } } // namespace v8::internal |
| 2898 | 2209 |
| 2899 #endif // V8_TARGET_ARCH_ARM | 2210 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |