| 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 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); | 288 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |
| 289 } | 289 } |
| 290 | 290 |
| 291 | 291 |
| 292 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 292 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
| 293 MacroAssembler* masm, | 293 MacroAssembler* masm, |
| 294 int index, | 294 int index, |
| 295 Register prototype, | 295 Register prototype, |
| 296 Label* miss) { | 296 Label* miss) { |
| 297 Isolate* isolate = masm->isolate(); | 297 Isolate* isolate = masm->isolate(); |
| 298 // Check we're still in the same context. | |
| 299 __ ldr(prototype, | |
| 300 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | |
| 301 __ Move(ip, isolate->global_object()); | |
| 302 __ cmp(prototype, ip); | |
| 303 __ b(ne, miss); | |
| 304 // Get the global function with the given index. | 298 // Get the global function with the given index. |
| 305 Handle<JSFunction> function( | 299 Handle<JSFunction> function( |
| 306 JSFunction::cast(isolate->native_context()->get(index))); | 300 JSFunction::cast(isolate->native_context()->get(index))); |
| 301 |
| 302 // Check we're still in the same context. |
| 303 Register scratch = prototype; |
| 304 const int offset = Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX); |
| 305 __ ldr(scratch, MemOperand(cp, offset)); |
| 306 __ ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); |
| 307 __ ldr(scratch, MemOperand(scratch, Context::SlotOffset(index))); |
| 308 __ Move(ip, function); |
| 309 __ cmp(ip, scratch); |
| 310 __ b(ne, miss); |
| 311 |
| 307 // Load its initial map. The global functions all have initial maps. | 312 // Load its initial map. The global functions all have initial maps. |
| 308 __ Move(prototype, Handle<Map>(function->initial_map())); | 313 __ Move(prototype, Handle<Map>(function->initial_map())); |
| 309 // Load the prototype from the initial map. | 314 // Load the prototype from the initial map. |
| 310 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); | 315 __ ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |
| 311 } | 316 } |
| 312 | 317 |
| 313 | 318 |
| 314 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, | 319 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, |
| 315 Register dst, | 320 Register dst, |
| 316 Register src, | 321 Register src, |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 const CallOptimization& optimization, | 786 const CallOptimization& optimization, |
| 782 int argc, | 787 int argc, |
| 783 Register holder_in, | 788 Register holder_in, |
| 784 bool restore_context) { | 789 bool restore_context) { |
| 785 ASSERT(optimization.is_simple_api_call()); | 790 ASSERT(optimization.is_simple_api_call()); |
| 786 | 791 |
| 787 // Abi for CallApiFunctionStub. | 792 // Abi for CallApiFunctionStub. |
| 788 Register callee = r0; | 793 Register callee = r0; |
| 789 Register call_data = r4; | 794 Register call_data = r4; |
| 790 Register holder = r2; | 795 Register holder = r2; |
| 791 Register api_function_address = r3; | 796 Register api_function_address = r1; |
| 792 Register thunk_arg = r1; | |
| 793 | 797 |
| 794 // Put holder in place. | 798 // Put holder in place. |
| 795 __ Move(holder, holder_in); | 799 __ Move(holder, holder_in); |
| 796 | 800 |
| 797 Isolate* isolate = masm->isolate(); | 801 Isolate* isolate = masm->isolate(); |
| 798 Handle<JSFunction> function = optimization.constant_function(); | 802 Handle<JSFunction> function = optimization.constant_function(); |
| 799 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 803 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 800 Handle<Object> call_data_obj(api_call_info->data(), isolate); | 804 Handle<Object> call_data_obj(api_call_info->data(), isolate); |
| 801 | 805 |
| 802 // Put callee in place. | 806 // Put callee in place. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 815 } | 819 } |
| 816 | 820 |
| 817 // Put api_function_address in place. | 821 // Put api_function_address in place. |
| 818 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 822 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 819 ApiFunction fun(function_address); | 823 ApiFunction fun(function_address); |
| 820 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; | 824 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; |
| 821 ExternalReference ref = ExternalReference(&fun, | 825 ExternalReference ref = ExternalReference(&fun, |
| 822 type, | 826 type, |
| 823 masm->isolate()); | 827 masm->isolate()); |
| 824 __ mov(api_function_address, Operand(ref)); | 828 __ mov(api_function_address, Operand(ref)); |
| 825 __ mov(thunk_arg, Operand(reinterpret_cast<int32_t>(function_address))); | |
| 826 | 829 |
| 827 // Jump to stub. | 830 // Jump to stub. |
| 828 CallApiFunctionStub stub(restore_context, call_data_undefined, argc); | 831 CallApiFunctionStub stub(restore_context, call_data_undefined, argc); |
| 829 __ TailCallStub(&stub); | 832 __ TailCallStub(&stub); |
| 830 } | 833 } |
| 831 | 834 |
| 832 | 835 |
| 833 // Generates call to API function. | |
| 834 static void GenerateFastApiCall(MacroAssembler* masm, | |
| 835 const CallOptimization& optimization, | |
| 836 int argc, | |
| 837 Handle<Map> map_to_holder, | |
| 838 CallOptimization::HolderLookup holder_lookup) { | |
| 839 Counters* counters = masm->isolate()->counters(); | |
| 840 __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r1); | |
| 841 | |
| 842 // Move holder to a register | |
| 843 Register holder_reg = r2; | |
| 844 switch (holder_lookup) { | |
| 845 case CallOptimization::kHolderIsReceiver: | |
| 846 { | |
| 847 ASSERT(map_to_holder.is_null()); | |
| 848 __ ldr(holder_reg, MemOperand(sp, argc * kPointerSize)); | |
| 849 } | |
| 850 break; | |
| 851 case CallOptimization::kHolderIsPrototypeOfMap: | |
| 852 { | |
| 853 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); | |
| 854 if (!masm->isolate()->heap()->InNewSpace(*holder)) { | |
| 855 __ Move(holder_reg, holder); | |
| 856 } else { | |
| 857 __ Move(holder_reg, map_to_holder); | |
| 858 __ ldr(holder_reg, | |
| 859 FieldMemOperand(holder_reg, Map::kPrototypeOffset)); | |
| 860 } | |
| 861 } | |
| 862 break; | |
| 863 case CallOptimization::kHolderNotFound: | |
| 864 UNREACHABLE(); | |
| 865 } | |
| 866 GenerateFastApiCallBody(masm, | |
| 867 optimization, | |
| 868 argc, | |
| 869 holder_reg, | |
| 870 false); | |
| 871 } | |
| 872 | |
| 873 | |
| 874 // Generate call to api function. | 836 // Generate call to api function. |
| 875 static void GenerateFastApiCall(MacroAssembler* masm, | 837 static void GenerateFastApiCall(MacroAssembler* masm, |
| 876 const CallOptimization& optimization, | 838 const CallOptimization& optimization, |
| 877 Register receiver, | 839 Register receiver, |
| 878 Register scratch, | 840 Register scratch, |
| 879 int argc, | 841 int argc, |
| 880 Register* values) { | 842 Register* values) { |
| 881 ASSERT(!receiver.is(scratch)); | 843 ASSERT(!receiver.is(scratch)); |
| 882 __ push(receiver); | 844 __ push(receiver); |
| 883 // Write the arguments to stack frame. | 845 // Write the arguments to stack frame. |
| 884 for (int i = 0; i < argc; i++) { | 846 for (int i = 0; i < argc; i++) { |
| 885 Register arg = values[argc-1-i]; | 847 Register arg = values[argc-1-i]; |
| 886 ASSERT(!receiver.is(arg)); | 848 ASSERT(!receiver.is(arg)); |
| 887 ASSERT(!scratch.is(arg)); | 849 ASSERT(!scratch.is(arg)); |
| 888 __ push(arg); | 850 __ push(arg); |
| 889 } | 851 } |
| 890 // Stack now matches JSFunction abi. | 852 // Stack now matches JSFunction abi. |
| 891 GenerateFastApiCallBody(masm, | 853 GenerateFastApiCallBody(masm, |
| 892 optimization, | 854 optimization, |
| 893 argc, | 855 argc, |
| 894 receiver, | 856 receiver, |
| 895 true); | 857 true); |
| 896 } | 858 } |
| 897 | 859 |
| 898 | 860 |
| 899 class CallInterceptorCompiler BASE_EMBEDDED { | |
| 900 public: | |
| 901 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | |
| 902 const ParameterCount& arguments, | |
| 903 Register name) | |
| 904 : stub_compiler_(stub_compiler), | |
| 905 arguments_(arguments), | |
| 906 name_(name) {} | |
| 907 | |
| 908 void Compile(MacroAssembler* masm, | |
| 909 Handle<JSObject> object, | |
| 910 Handle<JSObject> holder, | |
| 911 Handle<Name> name, | |
| 912 LookupResult* lookup, | |
| 913 Register receiver, | |
| 914 Register scratch1, | |
| 915 Register scratch2, | |
| 916 Register scratch3, | |
| 917 Label* miss) { | |
| 918 ASSERT(holder->HasNamedInterceptor()); | |
| 919 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 920 | |
| 921 // Check that the receiver isn't a smi. | |
| 922 __ JumpIfSmi(receiver, miss); | |
| 923 CallOptimization optimization(lookup); | |
| 924 if (optimization.is_constant_call()) { | |
| 925 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 926 holder, lookup, name, optimization, miss); | |
| 927 } else { | |
| 928 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 929 name, holder, miss); | |
| 930 } | |
| 931 } | |
| 932 | |
| 933 private: | |
| 934 void CompileCacheable(MacroAssembler* masm, | |
| 935 Handle<JSObject> object, | |
| 936 Register receiver, | |
| 937 Register scratch1, | |
| 938 Register scratch2, | |
| 939 Register scratch3, | |
| 940 Handle<JSObject> interceptor_holder, | |
| 941 LookupResult* lookup, | |
| 942 Handle<Name> name, | |
| 943 const CallOptimization& optimization, | |
| 944 Label* miss_label) { | |
| 945 ASSERT(optimization.is_constant_call()); | |
| 946 ASSERT(!lookup->holder()->IsGlobalObject()); | |
| 947 Counters* counters = masm->isolate()->counters(); | |
| 948 __ IncrementCounter(counters->call_const_interceptor(), 1, | |
| 949 scratch1, scratch2); | |
| 950 | |
| 951 // Check that the maps from receiver to interceptor's holder | |
| 952 // haven't changed and thus we can invoke interceptor. | |
| 953 Label miss_cleanup; | |
| 954 Register holder = | |
| 955 stub_compiler_->CheckPrototypes( | |
| 956 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 957 interceptor_holder, scratch1, scratch2, scratch3, | |
| 958 name, miss_label); | |
| 959 | |
| 960 // Invoke an interceptor and if it provides a value, | |
| 961 // branch to |regular_invoke|. | |
| 962 Label regular_invoke; | |
| 963 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, | |
| 964 ®ular_invoke); | |
| 965 | |
| 966 // Interceptor returned nothing for this property. Try to use cached | |
| 967 // constant function. | |
| 968 | |
| 969 // Check that the maps from interceptor's holder to constant function's | |
| 970 // holder haven't changed and thus we can use cached constant function. | |
| 971 if (*interceptor_holder != lookup->holder()) { | |
| 972 stub_compiler_->CheckPrototypes( | |
| 973 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | |
| 974 handle(lookup->holder()), scratch1, scratch2, scratch3, | |
| 975 name, miss_label); | |
| 976 } | |
| 977 | |
| 978 Handle<Map> lookup_map; | |
| 979 CallOptimization::HolderLookup holder_lookup = | |
| 980 CallOptimization::kHolderNotFound; | |
| 981 if (optimization.is_simple_api_call() && | |
| 982 !lookup->holder()->IsGlobalObject()) { | |
| 983 lookup_map = optimization.LookupHolderOfExpectedType( | |
| 984 object, object, interceptor_holder, &holder_lookup); | |
| 985 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 986 lookup_map = | |
| 987 optimization.LookupHolderOfExpectedType( | |
| 988 object, | |
| 989 interceptor_holder, | |
| 990 Handle<JSObject>(lookup->holder()), | |
| 991 &holder_lookup); | |
| 992 } | |
| 993 } | |
| 994 | |
| 995 // Invoke function. | |
| 996 if (holder_lookup != CallOptimization::kHolderNotFound) { | |
| 997 int argc = arguments_.immediate(); | |
| 998 GenerateFastApiCall(masm, | |
| 999 optimization, | |
| 1000 argc, | |
| 1001 lookup_map, | |
| 1002 holder_lookup); | |
| 1003 } else { | |
| 1004 Handle<JSFunction> function = optimization.constant_function(); | |
| 1005 __ Move(r0, receiver); | |
| 1006 stub_compiler_->GenerateJumpFunction(object, function); | |
| 1007 } | |
| 1008 | |
| 1009 // Invoke a regular function. | |
| 1010 __ bind(®ular_invoke); | |
| 1011 } | |
| 1012 | |
| 1013 void CompileRegular(MacroAssembler* masm, | |
| 1014 Handle<JSObject> object, | |
| 1015 Register receiver, | |
| 1016 Register scratch1, | |
| 1017 Register scratch2, | |
| 1018 Register scratch3, | |
| 1019 Handle<Name> name, | |
| 1020 Handle<JSObject> interceptor_holder, | |
| 1021 Label* miss_label) { | |
| 1022 Register holder = | |
| 1023 stub_compiler_->CheckPrototypes( | |
| 1024 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 1025 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); | |
| 1026 | |
| 1027 // Call a runtime function to load the interceptor property. | |
| 1028 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1029 // Save the name_ register across the call. | |
| 1030 __ push(name_); | |
| 1031 | |
| 1032 CompileCallLoadPropertyWithInterceptor( | |
| 1033 masm, receiver, holder, name_, interceptor_holder, | |
| 1034 IC::kLoadPropertyWithInterceptorForCall); | |
| 1035 | |
| 1036 // Restore the name_ register. | |
| 1037 __ pop(name_); | |
| 1038 // Leave the internal frame. | |
| 1039 } | |
| 1040 | |
| 1041 void LoadWithInterceptor(MacroAssembler* masm, | |
| 1042 Register receiver, | |
| 1043 Register holder, | |
| 1044 Handle<JSObject> holder_obj, | |
| 1045 Register scratch, | |
| 1046 Label* interceptor_succeeded) { | |
| 1047 { | |
| 1048 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1049 __ Push(receiver); | |
| 1050 __ Push(holder, name_); | |
| 1051 CompileCallLoadPropertyWithInterceptor( | |
| 1052 masm, receiver, holder, name_, holder_obj, | |
| 1053 IC::kLoadPropertyWithInterceptorOnly); | |
| 1054 __ pop(name_); | |
| 1055 __ pop(holder); | |
| 1056 __ pop(receiver); | |
| 1057 } | |
| 1058 // If interceptor returns no-result sentinel, call the constant function. | |
| 1059 __ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex); | |
| 1060 __ cmp(r0, scratch); | |
| 1061 __ b(ne, interceptor_succeeded); | |
| 1062 } | |
| 1063 | |
| 1064 CallStubCompiler* stub_compiler_; | |
| 1065 const ParameterCount& arguments_; | |
| 1066 Register name_; | |
| 1067 }; | |
| 1068 | |
| 1069 | |
| 1070 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 861 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1071 __ Jump(code, RelocInfo::CODE_TARGET); | 862 __ Jump(code, RelocInfo::CODE_TARGET); |
| 1072 } | 863 } |
| 1073 | 864 |
| 1074 | 865 |
| 1075 #undef __ | 866 #undef __ |
| 1076 #define __ ACCESS_MASM(masm()) | 867 #define __ ACCESS_MASM(masm()) |
| 1077 | 868 |
| 1078 | 869 |
| 1079 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, | 870 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1315 } | 1106 } |
| 1316 __ push(scratch3()); | 1107 __ push(scratch3()); |
| 1317 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); | 1108 __ LoadRoot(scratch3(), Heap::kUndefinedValueRootIndex); |
| 1318 __ mov(scratch4(), scratch3()); | 1109 __ mov(scratch4(), scratch3()); |
| 1319 __ Push(scratch3(), scratch4()); | 1110 __ Push(scratch3(), scratch4()); |
| 1320 __ mov(scratch4(), | 1111 __ mov(scratch4(), |
| 1321 Operand(ExternalReference::isolate_address(isolate()))); | 1112 Operand(ExternalReference::isolate_address(isolate()))); |
| 1322 __ Push(scratch4(), reg); | 1113 __ Push(scratch4(), reg); |
| 1323 __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_ | 1114 __ mov(scratch2(), sp); // scratch2 = PropertyAccessorInfo::args_ |
| 1324 __ push(name()); | 1115 __ push(name()); |
| 1325 __ mov(r0, sp); // r0 = Handle<Name> | |
| 1326 | 1116 |
| 1327 const int kApiStackSpace = 1; | 1117 // Abi for CallApiGetter |
| 1328 FrameScope frame_scope(masm(), StackFrame::MANUAL); | 1118 Register getter_address_reg = r2; |
| 1329 __ EnterExitFrame(false, kApiStackSpace); | |
| 1330 | 1119 |
| 1331 // Create PropertyAccessorInfo instance on the stack above the exit frame with | |
| 1332 // scratch2 (internal::Object** args_) as the data. | |
| 1333 __ str(scratch2(), MemOperand(sp, 1 * kPointerSize)); | |
| 1334 __ add(r1, sp, Operand(1 * kPointerSize)); // r1 = AccessorInfo& | |
| 1335 | |
| 1336 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; | |
| 1337 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1120 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1338 | |
| 1339 ApiFunction fun(getter_address); | 1121 ApiFunction fun(getter_address); |
| 1340 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; | 1122 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; |
| 1341 ExternalReference ref = ExternalReference(&fun, type, isolate()); | 1123 ExternalReference ref = ExternalReference(&fun, type, isolate()); |
| 1342 Register getter_address_reg = r3; | |
| 1343 Register thunk_last_arg = r2; | |
| 1344 __ mov(getter_address_reg, Operand(ref)); | 1124 __ mov(getter_address_reg, Operand(ref)); |
| 1345 __ mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(getter_address))); | |
| 1346 | 1125 |
| 1347 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback); | 1126 CallApiGetterStub stub; |
| 1348 ExternalReference::Type thunk_type = | 1127 __ TailCallStub(&stub); |
| 1349 ExternalReference::PROFILING_GETTER_CALL; | |
| 1350 ApiFunction thunk_fun(thunk_address); | |
| 1351 ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type, | |
| 1352 isolate()); | |
| 1353 __ CallApiFunctionAndReturn(getter_address_reg, | |
| 1354 thunk_ref, | |
| 1355 thunk_last_arg, | |
| 1356 kStackUnwindSpace, | |
| 1357 MemOperand(fp, 6 * kPointerSize), | |
| 1358 NULL); | |
| 1359 } | 1128 } |
| 1360 | 1129 |
| 1361 | 1130 |
| 1362 void LoadStubCompiler::GenerateLoadInterceptor( | 1131 void LoadStubCompiler::GenerateLoadInterceptor( |
| 1363 Register holder_reg, | 1132 Register holder_reg, |
| 1364 Handle<Object> object, | 1133 Handle<Object> object, |
| 1365 Handle<JSObject> interceptor_holder, | 1134 Handle<JSObject> interceptor_holder, |
| 1366 LookupResult* lookup, | 1135 LookupResult* lookup, |
| 1367 Handle<Name> name) { | 1136 Handle<Name> name) { |
| 1368 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1137 ASSERT(interceptor_holder->HasNamedInterceptor()); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1440 this->name(), interceptor_holder); | 1209 this->name(), interceptor_holder); |
| 1441 | 1210 |
| 1442 ExternalReference ref = | 1211 ExternalReference ref = |
| 1443 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1212 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
| 1444 isolate()); | 1213 isolate()); |
| 1445 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); | 1214 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); |
| 1446 } | 1215 } |
| 1447 } | 1216 } |
| 1448 | 1217 |
| 1449 | 1218 |
| 1450 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | |
| 1451 if (kind_ == Code::KEYED_CALL_IC) { | |
| 1452 __ cmp(r2, Operand(name)); | |
| 1453 __ b(ne, miss); | |
| 1454 } | |
| 1455 } | |
| 1456 | |
| 1457 | |
| 1458 void CallStubCompiler::GenerateFunctionCheck(Register function, | |
| 1459 Register scratch, | |
| 1460 Label* miss) { | |
| 1461 __ JumpIfSmi(function, miss); | |
| 1462 __ CompareObjectType(function, scratch, scratch, JS_FUNCTION_TYPE); | |
| 1463 __ b(ne, miss); | |
| 1464 } | |
| 1465 | |
| 1466 | |
| 1467 void CallStubCompiler::GenerateLoadFunctionFromCell( | |
| 1468 Handle<Cell> cell, | |
| 1469 Handle<JSFunction> function, | |
| 1470 Label* miss) { | |
| 1471 // Get the value from the cell. | |
| 1472 __ mov(r3, Operand(cell)); | |
| 1473 __ ldr(r1, FieldMemOperand(r3, Cell::kValueOffset)); | |
| 1474 | |
| 1475 // Check that the cell contains the same function. | |
| 1476 if (heap()->InNewSpace(*function)) { | |
| 1477 // We can't embed a pointer to a function in new space so we have | |
| 1478 // to verify that the shared function info is unchanged. This has | |
| 1479 // the nice side effect that multiple closures based on the same | |
| 1480 // function can all use this call IC. Before we load through the | |
| 1481 // function, we have to verify that it still is a function. | |
| 1482 GenerateFunctionCheck(r1, r3, miss); | |
| 1483 | |
| 1484 // Check the shared function info. Make sure it hasn't changed. | |
| 1485 __ Move(r3, Handle<SharedFunctionInfo>(function->shared())); | |
| 1486 __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
| 1487 __ cmp(r4, r3); | |
| 1488 } else { | |
| 1489 __ cmp(r1, Operand(function)); | |
| 1490 } | |
| 1491 __ b(ne, miss); | |
| 1492 } | |
| 1493 | |
| 1494 | |
| 1495 void CallStubCompiler::GenerateMissBranch() { | |
| 1496 Handle<Code> code = | |
| 1497 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | |
| 1498 kind_, | |
| 1499 extra_state()); | |
| 1500 __ Jump(code, RelocInfo::CODE_TARGET); | |
| 1501 } | |
| 1502 | |
| 1503 | |
| 1504 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | |
| 1505 Handle<JSObject> holder, | |
| 1506 PropertyIndex index, | |
| 1507 Handle<Name> name) { | |
| 1508 Label miss; | |
| 1509 | |
| 1510 Register reg = HandlerFrontendHeader( | |
| 1511 object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1512 GenerateFastPropertyLoad(masm(), r1, reg, index.is_inobject(holder), | |
| 1513 index.translate(holder), Representation::Tagged()); | |
| 1514 GenerateJumpFunction(object, r1, &miss); | |
| 1515 | |
| 1516 HandlerFrontendFooter(&miss); | |
| 1517 | |
| 1518 // Return the generated code. | |
| 1519 return GetCode(Code::FAST, name); | |
| 1520 } | |
| 1521 | |
| 1522 | |
| 1523 Handle<Code> CallStubCompiler::CompileFastApiCall( | |
| 1524 const CallOptimization& optimization, | |
| 1525 Handle<Object> object, | |
| 1526 Handle<JSObject> holder, | |
| 1527 Handle<Cell> cell, | |
| 1528 Handle<JSFunction> function, | |
| 1529 Handle<String> name) { | |
| 1530 Counters* counters = isolate()->counters(); | |
| 1531 | |
| 1532 ASSERT(optimization.is_simple_api_call()); | |
| 1533 // Bail out if object is a global object as we don't want to | |
| 1534 // repatch it to global receiver. | |
| 1535 if (object->IsGlobalObject()) return Handle<Code>::null(); | |
| 1536 if (!cell.is_null()) return Handle<Code>::null(); | |
| 1537 if (!object->IsJSObject()) return Handle<Code>::null(); | |
| 1538 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 1539 CallOptimization::HolderLookup holder_lookup = | |
| 1540 CallOptimization::kHolderNotFound; | |
| 1541 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( | |
| 1542 receiver, receiver, holder, &holder_lookup); | |
| 1543 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 1544 return Handle<Code>::null(); | |
| 1545 } | |
| 1546 | |
| 1547 Label miss; | |
| 1548 GenerateNameCheck(name, &miss); | |
| 1549 | |
| 1550 // Get the receiver from the stack. | |
| 1551 const int argc = arguments().immediate(); | |
| 1552 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
| 1553 | |
| 1554 // Check that the receiver isn't a smi. | |
| 1555 __ JumpIfSmi(r1, &miss); | |
| 1556 | |
| 1557 __ IncrementCounter(counters->call_const(), 1, r0, r3); | |
| 1558 | |
| 1559 // Check that the maps haven't changed and find a Holder as a side effect. | |
| 1560 CheckPrototypes( | |
| 1561 IC::CurrentTypeOf(object, isolate()), | |
| 1562 r1, holder, r0, r3, r4, name, &miss); | |
| 1563 | |
| 1564 GenerateFastApiCall( | |
| 1565 masm(), optimization, argc, lookup_map, holder_lookup); | |
| 1566 | |
| 1567 HandlerFrontendFooter(&miss); | |
| 1568 | |
| 1569 // Return the generated code. | |
| 1570 return GetCode(function); | |
| 1571 } | |
| 1572 | |
| 1573 | |
| 1574 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1219 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 1575 Label success; | 1220 Label success; |
| 1576 // Check that the object is a boolean. | 1221 // Check that the object is a boolean. |
| 1577 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1222 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1578 __ cmp(object, ip); | 1223 __ cmp(object, ip); |
| 1579 __ b(eq, &success); | 1224 __ b(eq, &success); |
| 1580 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 1225 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
| 1581 __ cmp(object, ip); | 1226 __ cmp(object, ip); |
| 1582 __ b(ne, miss); | 1227 __ b(ne, miss); |
| 1583 __ bind(&success); | 1228 __ bind(&success); |
| 1584 } | 1229 } |
| 1585 | 1230 |
| 1586 | 1231 |
| 1587 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { | |
| 1588 if (object->IsGlobalObject()) { | |
| 1589 const int argc = arguments().immediate(); | |
| 1590 const int receiver_offset = argc * kPointerSize; | |
| 1591 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); | |
| 1592 __ str(r3, MemOperand(sp, receiver_offset)); | |
| 1593 } | |
| 1594 } | |
| 1595 | |
| 1596 | |
| 1597 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, | |
| 1598 Handle<JSObject> holder, | |
| 1599 Handle<Name> name, | |
| 1600 CheckType check, | |
| 1601 Label* miss) { | |
| 1602 // ----------- S t a t e ------------- | |
| 1603 // -- r2 : name | |
| 1604 // -- lr : return address | |
| 1605 // ----------------------------------- | |
| 1606 GenerateNameCheck(name, miss); | |
| 1607 | |
| 1608 Register reg = r0; | |
| 1609 | |
| 1610 // Get the receiver from the stack | |
| 1611 const int argc = arguments().immediate(); | |
| 1612 const int receiver_offset = argc * kPointerSize; | |
| 1613 __ ldr(r0, MemOperand(sp, receiver_offset)); | |
| 1614 | |
| 1615 // Check that the receiver isn't a smi. | |
| 1616 if (check != NUMBER_CHECK) { | |
| 1617 __ JumpIfSmi(r0, miss); | |
| 1618 } | |
| 1619 | |
| 1620 // Make sure that it's okay not to patch the on stack receiver | |
| 1621 // unless we're doing a receiver map check. | |
| 1622 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | |
| 1623 switch (check) { | |
| 1624 case RECEIVER_MAP_CHECK: | |
| 1625 __ IncrementCounter(isolate()->counters()->call_const(), 1, r1, r3); | |
| 1626 | |
| 1627 // Check that the maps haven't changed. | |
| 1628 reg = CheckPrototypes( | |
| 1629 IC::CurrentTypeOf(object, isolate()), | |
| 1630 reg, holder, r1, r3, r4, name, miss); | |
| 1631 break; | |
| 1632 | |
| 1633 case STRING_CHECK: { | |
| 1634 // Check that the object is a string. | |
| 1635 __ CompareObjectType(reg, r3, r3, FIRST_NONSTRING_TYPE); | |
| 1636 __ b(ge, miss); | |
| 1637 // Check that the maps starting from the prototype haven't changed. | |
| 1638 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1639 masm(), Context::STRING_FUNCTION_INDEX, r1, miss); | |
| 1640 break; | |
| 1641 } | |
| 1642 case SYMBOL_CHECK: { | |
| 1643 // Check that the object is a symbol. | |
| 1644 __ CompareObjectType(reg, r3, r3, SYMBOL_TYPE); | |
| 1645 __ b(ne, miss); | |
| 1646 // Check that the maps starting from the prototype haven't changed. | |
| 1647 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1648 masm(), Context::SYMBOL_FUNCTION_INDEX, r1, miss); | |
| 1649 break; | |
| 1650 } | |
| 1651 case NUMBER_CHECK: { | |
| 1652 Label fast; | |
| 1653 // Check that the object is a smi or a heap number. | |
| 1654 __ JumpIfSmi(reg, &fast); | |
| 1655 __ CompareObjectType(reg, r3, r3, HEAP_NUMBER_TYPE); | |
| 1656 __ b(ne, miss); | |
| 1657 __ bind(&fast); | |
| 1658 // Check that the maps starting from the prototype haven't changed. | |
| 1659 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1660 masm(), Context::NUMBER_FUNCTION_INDEX, r1, miss); | |
| 1661 break; | |
| 1662 } | |
| 1663 case BOOLEAN_CHECK: { | |
| 1664 GenerateBooleanCheck(reg, miss); | |
| 1665 | |
| 1666 // Check that the maps starting from the prototype haven't changed. | |
| 1667 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1668 masm(), Context::BOOLEAN_FUNCTION_INDEX, r1, miss); | |
| 1669 break; | |
| 1670 } | |
| 1671 } | |
| 1672 | |
| 1673 if (check != RECEIVER_MAP_CHECK) { | |
| 1674 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); | |
| 1675 reg = CheckPrototypes( | |
| 1676 IC::CurrentTypeOf(prototype, isolate()), | |
| 1677 r1, holder, r1, r3, r4, name, miss); | |
| 1678 } | |
| 1679 | |
| 1680 return reg; | |
| 1681 } | |
| 1682 | |
| 1683 | |
| 1684 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, | |
| 1685 Register function, | |
| 1686 Label* miss) { | |
| 1687 ASSERT(function.is(r1)); | |
| 1688 // Check that the function really is a function. | |
| 1689 GenerateFunctionCheck(function, r3, miss); | |
| 1690 PatchImplicitReceiver(object); | |
| 1691 | |
| 1692 // Invoke the function. | |
| 1693 __ InvokeFunction(r1, arguments(), JUMP_FUNCTION, NullCallWrapper()); | |
| 1694 } | |
| 1695 | |
| 1696 | |
| 1697 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | |
| 1698 Handle<JSObject> holder, | |
| 1699 Handle<Name> name) { | |
| 1700 Label miss; | |
| 1701 GenerateNameCheck(name, &miss); | |
| 1702 | |
| 1703 // Get the number of arguments. | |
| 1704 const int argc = arguments().immediate(); | |
| 1705 LookupResult lookup(isolate()); | |
| 1706 LookupPostInterceptor(holder, name, &lookup); | |
| 1707 | |
| 1708 // Get the receiver from the stack. | |
| 1709 __ ldr(r1, MemOperand(sp, argc * kPointerSize)); | |
| 1710 | |
| 1711 CallInterceptorCompiler compiler(this, arguments(), r2); | |
| 1712 compiler.Compile(masm(), object, holder, name, &lookup, r1, r3, r4, r0, | |
| 1713 &miss); | |
| 1714 | |
| 1715 // Move returned value, the function to call, to r1. | |
| 1716 __ mov(r1, r0); | |
| 1717 // Restore receiver. | |
| 1718 __ ldr(r0, MemOperand(sp, argc * kPointerSize)); | |
| 1719 | |
| 1720 GenerateJumpFunction(object, r1, &miss); | |
| 1721 | |
| 1722 HandlerFrontendFooter(&miss); | |
| 1723 | |
| 1724 // Return the generated code. | |
| 1725 return GetCode(Code::FAST, name); | |
| 1726 } | |
| 1727 | |
| 1728 | |
| 1729 Handle<Code> CallStubCompiler::CompileCallGlobal( | |
| 1730 Handle<JSObject> object, | |
| 1731 Handle<GlobalObject> holder, | |
| 1732 Handle<PropertyCell> cell, | |
| 1733 Handle<JSFunction> function, | |
| 1734 Handle<Name> name) { | |
| 1735 if (HasCustomCallGenerator(function)) { | |
| 1736 Handle<Code> code = CompileCustomCall( | |
| 1737 object, holder, cell, function, Handle<String>::cast(name), | |
| 1738 Code::NORMAL); | |
| 1739 // A null handle means bail out to the regular compiler code below. | |
| 1740 if (!code.is_null()) return code; | |
| 1741 } | |
| 1742 | |
| 1743 Label miss; | |
| 1744 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1745 // Potentially loads a closure that matches the shared function info of the | |
| 1746 // function, rather than function. | |
| 1747 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 1748 | |
| 1749 Counters* counters = isolate()->counters(); | |
| 1750 __ IncrementCounter(counters->call_global_inline(), 1, r3, r4); | |
| 1751 GenerateJumpFunction(object, r1, function); | |
| 1752 HandlerFrontendFooter(&miss); | |
| 1753 | |
| 1754 // Return the generated code. | |
| 1755 return GetCode(Code::NORMAL, name); | |
| 1756 } | |
| 1757 | |
| 1758 | |
| 1759 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1232 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 1760 Handle<JSObject> object, | 1233 Handle<JSObject> object, |
| 1761 Handle<JSObject> holder, | 1234 Handle<JSObject> holder, |
| 1762 Handle<Name> name, | 1235 Handle<Name> name, |
| 1763 Handle<ExecutableAccessorInfo> callback) { | 1236 Handle<ExecutableAccessorInfo> callback) { |
| 1764 Register holder_reg = HandlerFrontend( | 1237 Register holder_reg = HandlerFrontend( |
| 1765 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | 1238 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 1766 | 1239 |
| 1767 // Stub never generated for non-global objects that require access checks. | 1240 // Stub never generated for non-global objects that require access checks. |
| 1768 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 1241 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1963 #define __ ACCESS_MASM(masm()) | 1436 #define __ ACCESS_MASM(masm()) |
| 1964 | 1437 |
| 1965 | 1438 |
| 1966 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 1439 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 1967 Handle<HeapType> type, | 1440 Handle<HeapType> type, |
| 1968 Handle<GlobalObject> global, | 1441 Handle<GlobalObject> global, |
| 1969 Handle<PropertyCell> cell, | 1442 Handle<PropertyCell> cell, |
| 1970 Handle<Name> name, | 1443 Handle<Name> name, |
| 1971 bool is_dont_delete) { | 1444 bool is_dont_delete) { |
| 1972 Label miss; | 1445 Label miss; |
| 1973 | |
| 1974 HandlerFrontendHeader(type, receiver(), global, name, &miss); | 1446 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 1975 | 1447 |
| 1976 // Get the value from the cell. | 1448 // Get the value from the cell. |
| 1977 __ mov(r3, Operand(cell)); | 1449 __ mov(r3, Operand(cell)); |
| 1978 __ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset)); | 1450 __ ldr(r4, FieldMemOperand(r3, Cell::kValueOffset)); |
| 1979 | 1451 |
| 1980 // Check for deleted property if property can actually be deleted. | 1452 // Check for deleted property if property can actually be deleted. |
| 1981 if (!is_dont_delete) { | 1453 if (!is_dont_delete) { |
| 1982 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 1454 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 1983 __ cmp(r4, ip); | 1455 __ cmp(r4, ip); |
| 1984 __ b(eq, &miss); | 1456 __ b(eq, &miss); |
| 1985 } | 1457 } |
| 1986 | 1458 |
| 1987 HandlerFrontendFooter(name, &miss); | |
| 1988 | |
| 1989 Counters* counters = isolate()->counters(); | 1459 Counters* counters = isolate()->counters(); |
| 1990 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); | 1460 __ IncrementCounter(counters->named_load_global_stub(), 1, r1, r3); |
| 1991 __ mov(r0, r4); | 1461 __ mov(r0, r4); |
| 1992 __ Ret(); | 1462 __ Ret(); |
| 1993 | 1463 |
| 1464 HandlerFrontendFooter(name, &miss); |
| 1465 |
| 1994 // Return the generated code. | 1466 // Return the generated code. |
| 1995 return GetCode(kind(), Code::NORMAL, name); | 1467 return GetCode(kind(), Code::NORMAL, name); |
| 1996 } | 1468 } |
| 1997 | 1469 |
| 1998 | 1470 |
| 1999 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 1471 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2000 TypeHandleList* types, | 1472 TypeHandleList* types, |
| 2001 CodeHandleList* handlers, | 1473 CodeHandleList* handlers, |
| 2002 Handle<Name> name, | 1474 Handle<Name> name, |
| 2003 Code::StubType type, | 1475 Code::StubType type, |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2120 // ----------------------------------- | 1592 // ----------------------------------- |
| 2121 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1593 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2122 } | 1594 } |
| 2123 | 1595 |
| 2124 | 1596 |
| 2125 #undef __ | 1597 #undef __ |
| 2126 | 1598 |
| 2127 } } // namespace v8::internal | 1599 } } // namespace v8::internal |
| 2128 | 1600 |
| 2129 #endif // V8_TARGET_ARCH_ARM | 1601 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |