| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); | 241 __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |
| 242 } | 242 } |
| 243 | 243 |
| 244 | 244 |
| 245 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 245 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
| 246 MacroAssembler* masm, | 246 MacroAssembler* masm, |
| 247 int index, | 247 int index, |
| 248 Register prototype, | 248 Register prototype, |
| 249 Label* miss) { | 249 Label* miss) { |
| 250 Isolate* isolate = masm->isolate(); | 250 Isolate* isolate = masm->isolate(); |
| 251 // Check we're still in the same context. | |
| 252 __ Ldr(prototype, GlobalObjectMemOperand()); | |
| 253 __ Cmp(prototype, Operand(isolate->global_object())); | |
| 254 __ B(ne, miss); | |
| 255 // Get the global function with the given index. | 251 // Get the global function with the given index. |
| 256 Handle<JSFunction> function( | 252 Handle<JSFunction> function( |
| 257 JSFunction::cast(isolate->native_context()->get(index))); | 253 JSFunction::cast(isolate->native_context()->get(index))); |
| 254 |
| 255 // Check we're still in the same context. |
| 256 Register scratch = prototype; |
| 257 __ Ldr(scratch, GlobalObjectMemOperand()); |
| 258 __ Ldr(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset)); |
| 259 __ Ldr(scratch, ContextMemOperand(scratch, index)); |
| 260 __ Cmp(scratch, Operand(function)); |
| 261 __ B(ne, miss); |
| 262 |
| 258 // Load its initial map. The global functions all have initial maps. | 263 // Load its initial map. The global functions all have initial maps. |
| 259 __ Mov(prototype, Operand(Handle<Map>(function->initial_map()))); | 264 __ Mov(prototype, Operand(Handle<Map>(function->initial_map()))); |
| 260 // Load the prototype from the initial map. | 265 // Load the prototype from the initial map. |
| 261 __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); | 266 __ Ldr(prototype, FieldMemOperand(prototype, Map::kPrototypeOffset)); |
| 262 } | 267 } |
| 263 | 268 |
| 264 | 269 |
| 265 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, | 270 void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, |
| 266 Register dst, | 271 Register dst, |
| 267 Register src, | 272 Register src, |
| (...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 | 746 |
| 742 static void GenerateFastApiCallBody(MacroAssembler* masm, | 747 static void GenerateFastApiCallBody(MacroAssembler* masm, |
| 743 const CallOptimization& optimization, | 748 const CallOptimization& optimization, |
| 744 int argc, | 749 int argc, |
| 745 Register holder_in, | 750 Register holder_in, |
| 746 bool restore_context) { | 751 bool restore_context) { |
| 747 ASSERT(optimization.is_simple_api_call()); | 752 ASSERT(optimization.is_simple_api_call()); |
| 748 | 753 |
| 749 // Abi for CallApiFunctionStub. | 754 // Abi for CallApiFunctionStub. |
| 750 Register callee = x0; | 755 Register callee = x0; |
| 751 Register thunk_arg = x1; | 756 Register call_data = x4; |
| 752 Register holder = x2; | 757 Register holder = x2; |
| 753 Register api_function_address = x3; | 758 Register api_function_address = x1; |
| 754 Register call_data = x4; | |
| 755 | 759 |
| 756 // Put holder in place. | 760 // Put holder in place. |
| 757 __ Mov(holder, holder_in); | 761 __ Mov(holder, holder_in); |
| 758 | 762 |
| 759 Isolate* isolate = masm->isolate(); | 763 Isolate* isolate = masm->isolate(); |
| 760 Handle<JSFunction> function = optimization.constant_function(); | 764 Handle<JSFunction> function = optimization.constant_function(); |
| 761 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 765 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 762 Handle<Object> call_data_obj(api_call_info->data(), isolate); | 766 Handle<Object> call_data_obj(api_call_info->data(), isolate); |
| 763 | 767 |
| 764 // Put callee in place. | 768 // Put callee in place. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 777 } | 781 } |
| 778 | 782 |
| 779 // Put api_function_address in place. | 783 // Put api_function_address in place. |
| 780 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 784 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
| 781 ApiFunction fun(function_address); | 785 ApiFunction fun(function_address); |
| 782 ExternalReference ref = ExternalReference(&fun, | 786 ExternalReference ref = ExternalReference(&fun, |
| 783 ExternalReference::DIRECT_API_CALL, | 787 ExternalReference::DIRECT_API_CALL, |
| 784 masm->isolate()); | 788 masm->isolate()); |
| 785 __ Mov(api_function_address, Operand(ref)); | 789 __ Mov(api_function_address, Operand(ref)); |
| 786 | 790 |
| 787 // Put thunk_arg in place. | |
| 788 __ Mov(thunk_arg, Operand(reinterpret_cast<intptr_t>(function_address))); | |
| 789 | |
| 790 // Jump to stub. | 791 // Jump to stub. |
| 791 CallApiFunctionStub stub(restore_context, call_data_undefined, argc); | 792 CallApiFunctionStub stub(restore_context, call_data_undefined, argc); |
| 792 __ TailCallStub(&stub); | 793 __ TailCallStub(&stub); |
| 793 } | 794 } |
| 794 | 795 |
| 795 | 796 |
| 796 // Generates call to API function. | |
| 797 static void GenerateFastApiCall(MacroAssembler* masm, | |
| 798 const CallOptimization& optimization, | |
| 799 int argc, | |
| 800 Handle<Map> map_to_holder, | |
| 801 CallOptimization::HolderLookup holder_lookup) { | |
| 802 Counters* counters = masm->isolate()->counters(); | |
| 803 __ IncrementCounter(counters->call_const_fast_api(), 1, x0, x1); | |
| 804 | |
| 805 // Move holder to a register | |
| 806 Register holder_reg = x2; | |
| 807 switch (holder_lookup) { | |
| 808 case CallOptimization::kHolderIsReceiver: | |
| 809 { | |
| 810 ASSERT(map_to_holder.is_null()); | |
| 811 __ Peek(holder_reg, argc * kPointerSize); | |
| 812 } | |
| 813 break; | |
| 814 case CallOptimization::kHolderIsPrototypeOfMap: | |
| 815 { | |
| 816 Handle<JSObject> holder(JSObject::cast(map_to_holder->prototype())); | |
| 817 if (!masm->isolate()->heap()->InNewSpace(*holder)) { | |
| 818 __ LoadObject(holder_reg, holder); | |
| 819 } else { | |
| 820 __ LoadObject(holder_reg, map_to_holder); | |
| 821 __ Ldr(holder_reg, | |
| 822 FieldMemOperand(holder_reg, Map::kPrototypeOffset)); | |
| 823 } | |
| 824 } | |
| 825 break; | |
| 826 case CallOptimization::kHolderNotFound: | |
| 827 UNREACHABLE(); | |
| 828 } | |
| 829 GenerateFastApiCallBody(masm, | |
| 830 optimization, | |
| 831 argc, | |
| 832 holder_reg, | |
| 833 false); | |
| 834 } | |
| 835 | |
| 836 | |
| 837 // Generate call to api function. | 797 // Generate call to api function. |
| 838 static void GenerateFastApiCall(MacroAssembler* masm, | 798 static void GenerateFastApiCall(MacroAssembler* masm, |
| 839 const CallOptimization& optimization, | 799 const CallOptimization& optimization, |
| 840 Register receiver, | 800 Register receiver, |
| 841 Register scratch, | 801 Register scratch, |
| 842 int argc, | 802 int argc, |
| 843 Register* values) { | 803 Register* values) { |
| 844 ASSERT(!AreAliased(receiver, scratch)); | 804 ASSERT(!AreAliased(receiver, scratch)); |
| 845 | 805 |
| 846 __ Push(receiver); | 806 __ Push(receiver); |
| 847 // Write the arguments to stack frame. | 807 // Write the arguments to stack frame. |
| 848 for (int i = 0; i < argc; i++) { | 808 for (int i = 0; i < argc; i++) { |
| 849 // TODO(all): Groups pushes to minimize Push overhead. | 809 // TODO(all): Groups pushes to minimize Push overhead. |
| 850 Register arg = values[argc-1-i]; | 810 Register arg = values[argc-1-i]; |
| 851 ASSERT(!receiver.is(arg)); | 811 ASSERT(!receiver.is(arg)); |
| 852 ASSERT(!scratch.is(arg)); | 812 ASSERT(!scratch.is(arg)); |
| 853 __ Push(arg); | 813 __ Push(arg); |
| 854 } | 814 } |
| 855 // Stack now matches JSFunction ABI. | 815 // Stack now matches JSFunction ABI. |
| 856 GenerateFastApiCallBody(masm, | 816 GenerateFastApiCallBody(masm, |
| 857 optimization, | 817 optimization, |
| 858 argc, | 818 argc, |
| 859 receiver, | 819 receiver, |
| 860 true); | 820 true); |
| 861 } | 821 } |
| 862 | 822 |
| 863 | 823 |
| 864 class CallInterceptorCompiler BASE_EMBEDDED { | |
| 865 public: | |
| 866 CallInterceptorCompiler(CallStubCompiler* stub_compiler, | |
| 867 const ParameterCount& arguments, | |
| 868 Register name) | |
| 869 : stub_compiler_(stub_compiler), | |
| 870 arguments_(arguments), | |
| 871 name_(name) { } | |
| 872 | |
| 873 void Compile(MacroAssembler* masm, | |
| 874 Handle<JSObject> object, | |
| 875 Handle<JSObject> holder, | |
| 876 Handle<Name> name, | |
| 877 LookupResult* lookup, | |
| 878 Register receiver, | |
| 879 Register scratch1, | |
| 880 Register scratch2, | |
| 881 Register scratch3, | |
| 882 Label* miss) { | |
| 883 ASSERT(holder->HasNamedInterceptor()); | |
| 884 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | |
| 885 | |
| 886 // Check that the receiver isn't a smi. | |
| 887 __ JumpIfSmi(receiver, miss); | |
| 888 | |
| 889 CallOptimization optimization(lookup); | |
| 890 if (optimization.is_constant_call()) { | |
| 891 CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 892 holder, lookup, name, optimization, miss); | |
| 893 } else { | |
| 894 CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3, | |
| 895 name, holder, miss); | |
| 896 } | |
| 897 } | |
| 898 | |
| 899 private: | |
| 900 void CompileCacheable(MacroAssembler* masm, | |
| 901 Handle<JSObject> object, | |
| 902 Register receiver, | |
| 903 Register scratch1, | |
| 904 Register scratch2, | |
| 905 Register scratch3, | |
| 906 Handle<JSObject> interceptor_holder, | |
| 907 LookupResult* lookup, | |
| 908 Handle<Name> name, | |
| 909 const CallOptimization& optimization, | |
| 910 Label* miss_label) { | |
| 911 ASSERT(optimization.is_constant_call()); | |
| 912 ASSERT(!lookup->holder()->IsGlobalObject()); | |
| 913 | |
| 914 Counters* counters = masm->isolate()->counters(); | |
| 915 __ IncrementCounter(counters->call_const_interceptor(), 1, | |
| 916 scratch1, scratch2); | |
| 917 | |
| 918 // Check that the maps from receiver to interceptor's holder | |
| 919 // haven't changed and thus we can invoke interceptor. | |
| 920 Label miss_cleanup; | |
| 921 Register holder = | |
| 922 stub_compiler_->CheckPrototypes( | |
| 923 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 924 interceptor_holder, scratch1, scratch2, scratch3, | |
| 925 name, miss_label); | |
| 926 | |
| 927 // Invoke an interceptor and if it provides a value, | |
| 928 // branch to |regular_invoke|. | |
| 929 Label regular_invoke; | |
| 930 LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, | |
| 931 ®ular_invoke); | |
| 932 | |
| 933 // Interceptor returned nothing for this property. Try to use cached | |
| 934 // constant function. | |
| 935 | |
| 936 // Check that the maps from interceptor's holder to constant function's | |
| 937 // holder haven't changed and thus we can use cached constant function. | |
| 938 if (*interceptor_holder != lookup->holder()) { | |
| 939 stub_compiler_->CheckPrototypes( | |
| 940 IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, | |
| 941 handle(lookup->holder()), scratch1, scratch2, scratch3, | |
| 942 name, miss_label); | |
| 943 } | |
| 944 | |
| 945 Handle<Map> lookup_map; | |
| 946 CallOptimization::HolderLookup holder_lookup = | |
| 947 CallOptimization::kHolderNotFound; | |
| 948 if (optimization.is_simple_api_call() && | |
| 949 !lookup->holder()->IsGlobalObject()) { | |
| 950 lookup_map = optimization.LookupHolderOfExpectedType( | |
| 951 object, object, interceptor_holder, &holder_lookup); | |
| 952 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 953 lookup_map = | |
| 954 optimization.LookupHolderOfExpectedType( | |
| 955 object, | |
| 956 interceptor_holder, | |
| 957 Handle<JSObject>(lookup->holder()), | |
| 958 &holder_lookup); | |
| 959 } | |
| 960 } | |
| 961 | |
| 962 // Invoke function. | |
| 963 if (holder_lookup != CallOptimization::kHolderNotFound) { | |
| 964 int argc = arguments_.immediate(); | |
| 965 GenerateFastApiCall(masm, | |
| 966 optimization, | |
| 967 argc, | |
| 968 lookup_map, | |
| 969 holder_lookup); | |
| 970 } else { | |
| 971 Handle<JSFunction> function = optimization.constant_function(); | |
| 972 __ Mov(x0, receiver); | |
| 973 stub_compiler_->GenerateJumpFunction(object, function); | |
| 974 } | |
| 975 | |
| 976 // Invoke a regular function. | |
| 977 __ Bind(®ular_invoke); | |
| 978 } | |
| 979 | |
| 980 void CompileRegular(MacroAssembler* masm, | |
| 981 Handle<JSObject> object, | |
| 982 Register receiver, | |
| 983 Register scratch1, | |
| 984 Register scratch2, | |
| 985 Register scratch3, | |
| 986 Handle<Name> name, | |
| 987 Handle<JSObject> interceptor_holder, | |
| 988 Label* miss_label) { | |
| 989 Register holder = | |
| 990 stub_compiler_->CheckPrototypes( | |
| 991 IC::CurrentTypeOf(object, masm->isolate()), receiver, | |
| 992 interceptor_holder, scratch1, scratch2, scratch3, name, miss_label); | |
| 993 | |
| 994 // Call a runtime function to load the interceptor property. | |
| 995 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 996 // The name_ register must be preserved across the call. | |
| 997 __ Push(name_); | |
| 998 | |
| 999 CompileCallLoadPropertyWithInterceptor( | |
| 1000 masm, receiver, holder, name_, interceptor_holder, | |
| 1001 IC::kLoadPropertyWithInterceptorForCall); | |
| 1002 | |
| 1003 __ Pop(name_); | |
| 1004 } | |
| 1005 | |
| 1006 | |
| 1007 void LoadWithInterceptor(MacroAssembler* masm, | |
| 1008 Register receiver, | |
| 1009 Register holder, | |
| 1010 Handle<JSObject> holder_obj, | |
| 1011 Register scratch, | |
| 1012 Label* interceptor_succeeded) { | |
| 1013 { | |
| 1014 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1015 __ Push(receiver, holder, name_); | |
| 1016 CompileCallLoadPropertyWithInterceptor( | |
| 1017 masm, receiver, holder, name_, holder_obj, | |
| 1018 IC::kLoadPropertyWithInterceptorOnly); | |
| 1019 // TODO(jbramley): We need two pops because holder and receiver can be | |
| 1020 // the same. In that case, we only need to preserve it once, but this is | |
| 1021 // fixed on ARM later anyway so I've left it alone for now. | |
| 1022 __ Pop(name_, holder); | |
| 1023 __ Pop(receiver); | |
| 1024 } | |
| 1025 | |
| 1026 // If interceptor returns no-result sentinel, call the constant function. | |
| 1027 __ JumpIfNotRoot(x0, | |
| 1028 Heap::kNoInterceptorResultSentinelRootIndex, | |
| 1029 interceptor_succeeded); | |
| 1030 } | |
| 1031 | |
| 1032 CallStubCompiler* stub_compiler_; | |
| 1033 const ParameterCount& arguments_; | |
| 1034 Register name_; | |
| 1035 }; | |
| 1036 | |
| 1037 | |
| 1038 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { | 824 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) { |
| 1039 __ Jump(code, RelocInfo::CODE_TARGET); | 825 __ Jump(code, RelocInfo::CODE_TARGET); |
| 1040 } | 826 } |
| 1041 | 827 |
| 1042 | 828 |
| 1043 #undef __ | 829 #undef __ |
| 1044 #define __ ACCESS_MASM(masm()) | 830 #define __ ACCESS_MASM(masm()) |
| 1045 | 831 |
| 1046 | 832 |
| 1047 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, | 833 Register StubCompiler::CheckPrototypes(Handle<HeapType> type, |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1301 __ Add(args_addr, __ StackPointer(), kPointerSize); | 1087 __ Add(args_addr, __ StackPointer(), kPointerSize); |
| 1302 | 1088 |
| 1303 // Stack at this point: | 1089 // Stack at this point: |
| 1304 // sp[40] callback data | 1090 // sp[40] callback data |
| 1305 // sp[32] undefined | 1091 // sp[32] undefined |
| 1306 // sp[24] undefined | 1092 // sp[24] undefined |
| 1307 // sp[16] isolate | 1093 // sp[16] isolate |
| 1308 // args_addr -> sp[8] reg | 1094 // args_addr -> sp[8] reg |
| 1309 // sp[0] name | 1095 // sp[0] name |
| 1310 | 1096 |
| 1311 // Pass the Handle<Name> of the property name to the runtime. | 1097 // Abi for CallApiGetter. |
| 1312 __ Mov(x0, __ StackPointer()); | 1098 Register getter_address_reg = x2; |
| 1313 | |
| 1314 FrameScope frame_scope(masm(), StackFrame::MANUAL); | |
| 1315 const int kApiStackSpace = 1; | |
| 1316 __ EnterExitFrame(false, scratch4(), | |
| 1317 kApiStackSpace + MacroAssembler::kCallApiFunctionSpillSpace); | |
| 1318 | |
| 1319 // Create PropertyAccessorInfo instance on the stack above the exit frame | |
| 1320 // (before the return address) with args_addr as the data. | |
| 1321 __ Poke(args_addr, 1 * kPointerSize); | |
| 1322 | |
| 1323 // Get the address of ExecutableAccessorInfo instance and pass it to the | |
| 1324 // runtime. | |
| 1325 __ Add(x1, __ StackPointer(), 1 * kPointerSize); | |
| 1326 | |
| 1327 // CallApiFunctionAndReturn can spill registers inside the exit frame, after | |
| 1328 // the return address and the ExecutableAccessorInfo instance. | |
| 1329 const int spill_offset = 1 + kApiStackSpace; | |
| 1330 | |
| 1331 // After the call to the API function we need to free memory used for: | |
| 1332 // - the holder | |
| 1333 // - the callback data | |
| 1334 // - the isolate | |
| 1335 // - the property name | |
| 1336 // - the receiver. | |
| 1337 // | |
| 1338 // The memory allocated inside the ExitFrame will be freed when we'll leave | |
| 1339 // the ExitFrame in CallApiFunctionAndReturn. | |
| 1340 const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1; | |
| 1341 | 1099 |
| 1342 // Set up the call. | 1100 // Set up the call. |
| 1343 Address getter_address = v8::ToCData<Address>(callback->getter()); | 1101 Address getter_address = v8::ToCData<Address>(callback->getter()); |
| 1344 ApiFunction fun(getter_address); | 1102 ApiFunction fun(getter_address); |
| 1345 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; | 1103 ExternalReference::Type type = ExternalReference::DIRECT_GETTER_CALL; |
| 1346 ExternalReference ref = ExternalReference(&fun, type, isolate()); | 1104 ExternalReference ref = ExternalReference(&fun, type, isolate()); |
| 1347 Register getter_address_reg = x3; | |
| 1348 Register thunk_last_arg = x2; | |
| 1349 __ Mov(getter_address_reg, Operand(ref)); | 1105 __ Mov(getter_address_reg, Operand(ref)); |
| 1350 __ Mov(thunk_last_arg, Operand(reinterpret_cast<intptr_t>(getter_address))); | |
| 1351 | 1106 |
| 1352 Address thunk_address = FUNCTION_ADDR(&InvokeAccessorGetterCallback); | 1107 CallApiGetterStub stub; |
| 1353 ExternalReference::Type thunk_type = ExternalReference::PROFILING_GETTER_CALL; | 1108 __ TailCallStub(&stub); |
| 1354 ApiFunction thunk_fun(thunk_address); | |
| 1355 ExternalReference thunk_ref = | |
| 1356 ExternalReference(&thunk_fun, thunk_type, isolate()); | |
| 1357 | |
| 1358 __ CallApiFunctionAndReturn(getter_address_reg, | |
| 1359 thunk_ref, | |
| 1360 thunk_last_arg, | |
| 1361 kStackUnwindSpace, | |
| 1362 spill_offset, | |
| 1363 MemOperand(fp, 6 * kPointerSize), | |
| 1364 NULL); | |
| 1365 } | 1109 } |
| 1366 | 1110 |
| 1367 | 1111 |
| 1368 void LoadStubCompiler::GenerateLoadInterceptor( | 1112 void LoadStubCompiler::GenerateLoadInterceptor( |
| 1369 Register holder_reg, | 1113 Register holder_reg, |
| 1370 Handle<Object> object, | 1114 Handle<Object> object, |
| 1371 Handle<JSObject> interceptor_holder, | 1115 Handle<JSObject> interceptor_holder, |
| 1372 LookupResult* lookup, | 1116 LookupResult* lookup, |
| 1373 Handle<Name> name) { | 1117 Handle<Name> name) { |
| 1374 ASSERT(!AreAliased(receiver(), this->name(), | 1118 ASSERT(!AreAliased(receiver(), this->name(), |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1446 masm(), receiver(), holder_reg, this->name(), interceptor_holder); | 1190 masm(), receiver(), holder_reg, this->name(), interceptor_holder); |
| 1447 | 1191 |
| 1448 ExternalReference ref = | 1192 ExternalReference ref = |
| 1449 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1193 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
| 1450 isolate()); | 1194 isolate()); |
| 1451 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); | 1195 __ TailCallExternalReference(ref, StubCache::kInterceptorArgsLength, 1); |
| 1452 } | 1196 } |
| 1453 } | 1197 } |
| 1454 | 1198 |
| 1455 | 1199 |
| 1456 void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { | |
| 1457 Register name_reg = x2; | |
| 1458 | |
| 1459 if (kind_ == Code::KEYED_CALL_IC) { | |
| 1460 __ Cmp(name_reg, Operand(name)); | |
| 1461 __ B(ne, miss); | |
| 1462 } | |
| 1463 } | |
| 1464 | |
| 1465 | |
| 1466 void CallStubCompiler::GenerateFunctionCheck(Register function, | |
| 1467 Register scratch, | |
| 1468 Label* miss) { | |
| 1469 __ JumpIfSmi(function, miss); | |
| 1470 __ JumpIfNotObjectType(function, scratch, scratch, JS_FUNCTION_TYPE, miss); | |
| 1471 } | |
| 1472 | |
| 1473 | |
| 1474 // Load the function object into x1 register. | |
| 1475 void CallStubCompiler::GenerateLoadFunctionFromCell( | |
| 1476 Handle<Cell> cell, | |
| 1477 Handle<JSFunction> function, | |
| 1478 Label* miss) { | |
| 1479 // Get the value from the cell. | |
| 1480 __ Mov(x3, Operand(cell)); | |
| 1481 Register function_reg = x1; | |
| 1482 __ Ldr(function_reg, FieldMemOperand(x3, Cell::kValueOffset)); | |
| 1483 | |
| 1484 // Check that the cell contains the same function. | |
| 1485 if (heap()->InNewSpace(*function)) { | |
| 1486 // We can't embed a pointer to a function in new space so we have | |
| 1487 // to verify that the shared function info is unchanged. This has | |
| 1488 // the nice side effect that multiple closures based on the same | |
| 1489 // function can all use this call IC. Before we load through the | |
| 1490 // function, we have to verify that it still is a function. | |
| 1491 GenerateFunctionCheck(function_reg, x3, miss); | |
| 1492 | |
| 1493 // Check the shared function info. Make sure it hasn't changed. | |
| 1494 __ Mov(x3, Operand(Handle<SharedFunctionInfo>(function->shared()))); | |
| 1495 __ Ldr(x4, | |
| 1496 FieldMemOperand(function_reg, JSFunction::kSharedFunctionInfoOffset)); | |
| 1497 __ Cmp(x4, x3); | |
| 1498 } else { | |
| 1499 __ Cmp(function_reg, Operand(function)); | |
| 1500 } | |
| 1501 __ B(ne, miss); | |
| 1502 } | |
| 1503 | |
| 1504 | |
| 1505 void CallStubCompiler::GenerateMissBranch() { | |
| 1506 Handle<Code> code = | |
| 1507 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | |
| 1508 kind_, | |
| 1509 extra_state()); | |
| 1510 __ Jump(code, RelocInfo::CODE_TARGET); | |
| 1511 } | |
| 1512 | |
| 1513 | |
| 1514 Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, | |
| 1515 Handle<JSObject> holder, | |
| 1516 PropertyIndex index, | |
| 1517 Handle<Name> name) { | |
| 1518 Label miss; | |
| 1519 Register function = x1; | |
| 1520 | |
| 1521 Register holder_reg = HandlerFrontendHeader( | |
| 1522 object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1523 | |
| 1524 GenerateFastPropertyLoad(masm(), function, holder_reg, | |
| 1525 index.is_inobject(holder), | |
| 1526 index.translate(holder), | |
| 1527 Representation::Tagged()); | |
| 1528 GenerateJumpFunction(object, function, &miss); | |
| 1529 | |
| 1530 HandlerFrontendFooter(&miss); | |
| 1531 | |
| 1532 // Return the generated code. | |
| 1533 return GetCode(Code::FAST, name); | |
| 1534 } | |
| 1535 | |
| 1536 | |
| 1537 Handle<Code> CallStubCompiler::CompileFastApiCall( | |
| 1538 const CallOptimization& optimization, | |
| 1539 Handle<Object> object, | |
| 1540 Handle<JSObject> holder, | |
| 1541 Handle<Cell> cell, | |
| 1542 Handle<JSFunction> function, | |
| 1543 Handle<String> name) { | |
| 1544 Counters* counters = isolate()->counters(); | |
| 1545 | |
| 1546 ASSERT(optimization.is_simple_api_call()); | |
| 1547 // Bail out if object is a global object as we don't want to | |
| 1548 // repatch it to global receiver. | |
| 1549 if (object->IsGlobalObject()) return Handle<Code>::null(); | |
| 1550 if (!cell.is_null()) return Handle<Code>::null(); | |
| 1551 if (!object->IsJSObject()) return Handle<Code>::null(); | |
| 1552 Handle<JSObject> receiver = Handle<JSObject>::cast(object); | |
| 1553 CallOptimization::HolderLookup holder_lookup = | |
| 1554 CallOptimization::kHolderNotFound; | |
| 1555 Handle<Map> lookup_map = optimization.LookupHolderOfExpectedType( | |
| 1556 receiver, receiver, holder, &holder_lookup); | |
| 1557 if (holder_lookup == CallOptimization::kHolderNotFound) { | |
| 1558 return Handle<Code>::null(); | |
| 1559 } | |
| 1560 | |
| 1561 Label miss; | |
| 1562 GenerateNameCheck(name, &miss); | |
| 1563 | |
| 1564 const int argc = arguments().immediate(); | |
| 1565 | |
| 1566 // Get the receiver from the stack. | |
| 1567 Register receiver_reg = x1; | |
| 1568 __ Peek(receiver_reg, argc * kPointerSize); | |
| 1569 | |
| 1570 // Check that the receiver isn't a smi. | |
| 1571 __ JumpIfSmi(receiver_reg, &miss); | |
| 1572 | |
| 1573 __ IncrementCounter(counters->call_const(), 1, x0, x3); | |
| 1574 | |
| 1575 // Check that the maps haven't changed and find a Holder as a side effect. | |
| 1576 CheckPrototypes(IC::CurrentTypeOf(object, isolate()), | |
| 1577 receiver_reg, holder, x0, x3, x4, name, &miss); | |
| 1578 | |
| 1579 GenerateFastApiCall( | |
| 1580 masm(), optimization, argc, lookup_map, holder_lookup); | |
| 1581 | |
| 1582 HandlerFrontendFooter(&miss); | |
| 1583 | |
| 1584 // Return the generated code. | |
| 1585 return GetCode(function); | |
| 1586 } | |
| 1587 | |
| 1588 | |
| 1589 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { | 1200 void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
| 1590 Label success; | 1201 Label success; |
| 1591 // Check that the object is a boolean. | 1202 // Check that the object is a boolean. |
| 1592 // TODO(all): Optimize this like LCodeGen::DoDeferredTaggedToI. | 1203 // TODO(all): Optimize this like LCodeGen::DoDeferredTaggedToI. |
| 1593 __ JumpIfRoot(object, Heap::kTrueValueRootIndex, &success); | 1204 __ JumpIfRoot(object, Heap::kTrueValueRootIndex, &success); |
| 1594 __ JumpIfNotRoot(object, Heap::kFalseValueRootIndex, miss); | 1205 __ JumpIfNotRoot(object, Heap::kFalseValueRootIndex, miss); |
| 1595 __ Bind(&success); | 1206 __ Bind(&success); |
| 1596 } | 1207 } |
| 1597 | 1208 |
| 1598 | 1209 |
| 1599 void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) { | |
| 1600 // TODO(all): Is the use of x3 significant? | |
| 1601 if (object->IsGlobalObject()) { | |
| 1602 const int argc = arguments().immediate(); | |
| 1603 const int receiver_offset = argc * kPointerSize; | |
| 1604 __ LoadRoot(x3, Heap::kUndefinedValueRootIndex); | |
| 1605 __ Poke(x3, receiver_offset); | |
| 1606 } | |
| 1607 } | |
| 1608 | |
| 1609 | |
| 1610 Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, | |
| 1611 Handle<JSObject> holder, | |
| 1612 Handle<Name> name, | |
| 1613 CheckType check, | |
| 1614 Label* miss) { | |
| 1615 // ----------- S t a t e ------------- | |
| 1616 // -- x2 : name | |
| 1617 // -- lr : return address | |
| 1618 // ----------------------------------- | |
| 1619 GenerateNameCheck(name, miss); | |
| 1620 | |
| 1621 Register receiver = x0; | |
| 1622 Register prototype_reg = x1; | |
| 1623 | |
| 1624 // Get the receiver from the stack. | |
| 1625 const int argc = arguments().immediate(); | |
| 1626 const int receiver_offset = argc * kPointerSize; | |
| 1627 __ Peek(receiver, receiver_offset); | |
| 1628 | |
| 1629 // Check that the receiver isn't a smi. | |
| 1630 if (check != NUMBER_CHECK) { | |
| 1631 __ JumpIfSmi(receiver, miss); | |
| 1632 } | |
| 1633 | |
| 1634 // Make sure that it's okay not to patch the on stack receiver | |
| 1635 // unless we're doing a receiver map check. | |
| 1636 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | |
| 1637 | |
| 1638 switch (check) { | |
| 1639 case RECEIVER_MAP_CHECK: { | |
| 1640 __ IncrementCounter(isolate()->counters()->call_const(), 1, x1, x3); | |
| 1641 | |
| 1642 // Check that the maps haven't changed. | |
| 1643 receiver = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), | |
| 1644 receiver, holder, x1, x3, x4, name, miss); | |
| 1645 break; | |
| 1646 } | |
| 1647 case STRING_CHECK: { | |
| 1648 // Check that the object is a string. | |
| 1649 __ JumpIfObjectType(receiver, x3, x3, FIRST_NONSTRING_TYPE, miss, ge); | |
| 1650 // Check that the maps starting from the prototype_reg haven't changed. | |
| 1651 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1652 masm(), Context::STRING_FUNCTION_INDEX, prototype_reg, miss); | |
| 1653 break; | |
| 1654 } | |
| 1655 case SYMBOL_CHECK: { | |
| 1656 // Check that the object is a symbol. | |
| 1657 __ JumpIfNotObjectType(receiver, x3, x3, SYMBOL_TYPE, miss); | |
| 1658 // Check that the maps starting from the prototype_reg haven't changed. | |
| 1659 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1660 masm(), Context::SYMBOL_FUNCTION_INDEX, prototype_reg, miss); | |
| 1661 break; | |
| 1662 } | |
| 1663 case NUMBER_CHECK: { | |
| 1664 Label fast; | |
| 1665 // Check that the object is a smi or a heap number. | |
| 1666 __ JumpIfSmi(receiver, &fast); | |
| 1667 __ JumpIfNotObjectType(receiver, x3, x3, HEAP_NUMBER_TYPE, miss); | |
| 1668 | |
| 1669 __ Bind(&fast); | |
| 1670 // Check that the maps starting from the prototype_reg haven't changed. | |
| 1671 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1672 masm(), Context::NUMBER_FUNCTION_INDEX, prototype_reg, miss); | |
| 1673 break; | |
| 1674 } | |
| 1675 case BOOLEAN_CHECK: { | |
| 1676 GenerateBooleanCheck(receiver, miss); | |
| 1677 | |
| 1678 // Check that the maps starting from the prototype_reg haven't changed. | |
| 1679 GenerateDirectLoadGlobalFunctionPrototype( | |
| 1680 masm(), Context::BOOLEAN_FUNCTION_INDEX, prototype_reg, miss); | |
| 1681 break; | |
| 1682 } | |
| 1683 } | |
| 1684 | |
| 1685 if (check != RECEIVER_MAP_CHECK) { | |
| 1686 Handle<Object> prototype(object->GetPrototype(isolate()), isolate()); | |
| 1687 receiver = CheckPrototypes( | |
| 1688 IC::CurrentTypeOf(prototype, isolate()), | |
| 1689 prototype_reg, holder, x1, x3, x4, name, miss); | |
| 1690 } | |
| 1691 | |
| 1692 return receiver; | |
| 1693 } | |
| 1694 | |
| 1695 | |
| 1696 void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, | |
| 1697 Register function, | |
| 1698 Label* miss) { | |
| 1699 ASSERT(function.Is(x1)); | |
| 1700 // Check that the function really is a function. | |
| 1701 GenerateFunctionCheck(function, x3, miss); | |
| 1702 PatchImplicitReceiver(object); | |
| 1703 | |
| 1704 // Invoke the function. | |
| 1705 __ InvokeFunction(function, arguments(), JUMP_FUNCTION, NullCallWrapper()); | |
| 1706 } | |
| 1707 | |
| 1708 | |
| 1709 Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, | |
| 1710 Handle<JSObject> holder, | |
| 1711 Handle<Name> name) { | |
| 1712 Label miss; | |
| 1713 Register name_reg = x2; | |
| 1714 | |
| 1715 GenerateNameCheck(name, &miss); | |
| 1716 | |
| 1717 const int argc = arguments().immediate(); | |
| 1718 LookupResult lookup(isolate()); | |
| 1719 LookupPostInterceptor(holder, name, &lookup); | |
| 1720 | |
| 1721 // Get the receiver from the stack. | |
| 1722 Register receiver = x5; | |
| 1723 __ Peek(receiver, argc * kPointerSize); | |
| 1724 | |
| 1725 CallInterceptorCompiler compiler(this, arguments(), name_reg); | |
| 1726 compiler.Compile( | |
| 1727 masm(), object, holder, name, &lookup, receiver, x3, x4, x0, &miss); | |
| 1728 | |
| 1729 // Move returned value, the function to call, to x1 (this is required by | |
| 1730 // GenerateCallFunction). | |
| 1731 Register function = x1; | |
| 1732 __ Mov(function, x0); | |
| 1733 | |
| 1734 // Restore receiver. | |
| 1735 __ Peek(receiver, argc * kPointerSize); | |
| 1736 | |
| 1737 GenerateJumpFunction(object, x1, &miss); | |
| 1738 | |
| 1739 HandlerFrontendFooter(&miss); | |
| 1740 | |
| 1741 // Return the generated code. | |
| 1742 return GetCode(Code::FAST, name); | |
| 1743 } | |
| 1744 | |
| 1745 | |
| 1746 Handle<Code> CallStubCompiler::CompileCallGlobal( | |
| 1747 Handle<JSObject> object, | |
| 1748 Handle<GlobalObject> holder, | |
| 1749 Handle<PropertyCell> cell, | |
| 1750 Handle<JSFunction> function, | |
| 1751 Handle<Name> name) { | |
| 1752 if (HasCustomCallGenerator(function)) { | |
| 1753 Handle<Code> code = CompileCustomCall( | |
| 1754 object, holder, cell, function, Handle<String>::cast(name), | |
| 1755 Code::NORMAL); | |
| 1756 // A null handle means bail out to the regular compiler code below. | |
| 1757 if (!code.is_null()) return code; | |
| 1758 } | |
| 1759 | |
| 1760 Label miss; | |
| 1761 HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss); | |
| 1762 // Potentially loads a closure that matches the shared function info of the | |
| 1763 // function, rather than function. | |
| 1764 GenerateLoadFunctionFromCell(cell, function, &miss); | |
| 1765 // After these two calls the receiver is left in x0 and the function in x1. | |
| 1766 Register function_reg = x1; | |
| 1767 | |
| 1768 Counters* counters = isolate()->counters(); | |
| 1769 __ IncrementCounter(counters->call_global_inline(), 1, x3, x4); | |
| 1770 GenerateJumpFunction(object, function_reg, function); | |
| 1771 HandlerFrontendFooter(&miss); | |
| 1772 | |
| 1773 // Return the generated code. | |
| 1774 return GetCode(Code::NORMAL, name); | |
| 1775 } | |
| 1776 | |
| 1777 | |
| 1778 Handle<Code> StoreStubCompiler::CompileStoreCallback( | 1210 Handle<Code> StoreStubCompiler::CompileStoreCallback( |
| 1779 Handle<JSObject> object, | 1211 Handle<JSObject> object, |
| 1780 Handle<JSObject> holder, | 1212 Handle<JSObject> holder, |
| 1781 Handle<Name> name, | 1213 Handle<Name> name, |
| 1782 Handle<ExecutableAccessorInfo> callback) { | 1214 Handle<ExecutableAccessorInfo> callback) { |
| 1783 ASM_LOCATION("StoreStubCompiler::CompileStoreCallback"); | 1215 ASM_LOCATION("StoreStubCompiler::CompileStoreCallback"); |
| 1784 Register holder_reg = HandlerFrontend( | 1216 Register holder_reg = HandlerFrontend( |
| 1785 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); | 1217 IC::CurrentTypeOf(object, isolate()), receiver(), holder, name); |
| 1786 | 1218 |
| 1787 // Stub never generated for non-global objects that require access checks. | 1219 // Stub never generated for non-global objects that require access checks. |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1971 #define __ ACCESS_MASM(masm()) | 1403 #define __ ACCESS_MASM(masm()) |
| 1972 | 1404 |
| 1973 | 1405 |
| 1974 Handle<Code> LoadStubCompiler::CompileLoadGlobal( | 1406 Handle<Code> LoadStubCompiler::CompileLoadGlobal( |
| 1975 Handle<HeapType> type, | 1407 Handle<HeapType> type, |
| 1976 Handle<GlobalObject> global, | 1408 Handle<GlobalObject> global, |
| 1977 Handle<PropertyCell> cell, | 1409 Handle<PropertyCell> cell, |
| 1978 Handle<Name> name, | 1410 Handle<Name> name, |
| 1979 bool is_dont_delete) { | 1411 bool is_dont_delete) { |
| 1980 Label miss; | 1412 Label miss; |
| 1981 | |
| 1982 HandlerFrontendHeader(type, receiver(), global, name, &miss); | 1413 HandlerFrontendHeader(type, receiver(), global, name, &miss); |
| 1983 | 1414 |
| 1984 // Get the value from the cell. | 1415 // Get the value from the cell. |
| 1985 __ Mov(x3, Operand(cell)); | 1416 __ Mov(x3, Operand(cell)); |
| 1986 __ Ldr(x4, FieldMemOperand(x3, Cell::kValueOffset)); | 1417 __ Ldr(x4, FieldMemOperand(x3, Cell::kValueOffset)); |
| 1987 | 1418 |
| 1988 // Check for deleted property if property can actually be deleted. | 1419 // Check for deleted property if property can actually be deleted. |
| 1989 if (!is_dont_delete) { | 1420 if (!is_dont_delete) { |
| 1990 __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &miss); | 1421 __ JumpIfRoot(x4, Heap::kTheHoleValueRootIndex, &miss); |
| 1991 } | 1422 } |
| 1992 | 1423 |
| 1993 HandlerFrontendFooter(name, &miss); | |
| 1994 | |
| 1995 Counters* counters = isolate()->counters(); | 1424 Counters* counters = isolate()->counters(); |
| 1996 __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3); | 1425 __ IncrementCounter(counters->named_load_global_stub(), 1, x1, x3); |
| 1997 __ Mov(x0, x4); | 1426 __ Mov(x0, x4); |
| 1998 __ Ret(); | 1427 __ Ret(); |
| 1999 | 1428 |
| 1429 HandlerFrontendFooter(name, &miss); |
| 1430 |
| 2000 // Return the generated code. | 1431 // Return the generated code. |
| 2001 return GetCode(kind(), Code::NORMAL, name); | 1432 return GetCode(kind(), Code::NORMAL, name); |
| 2002 } | 1433 } |
| 2003 | 1434 |
| 2004 | 1435 |
| 2005 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( | 1436 Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC( |
| 2006 TypeHandleList* types, | 1437 TypeHandleList* types, |
| 2007 CodeHandleList* handlers, | 1438 CodeHandleList* handlers, |
| 2008 Handle<Name> name, | 1439 Handle<Name> name, |
| 2009 Code::StubType type, | 1440 Code::StubType type, |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2130 | 1561 |
| 2131 // Miss case, call the runtime. | 1562 // Miss case, call the runtime. |
| 2132 __ Bind(&miss); | 1563 __ Bind(&miss); |
| 2133 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); | 1564 TailCallBuiltin(masm, Builtins::kKeyedLoadIC_Miss); |
| 2134 } | 1565 } |
| 2135 | 1566 |
| 2136 | 1567 |
| 2137 } } // namespace v8::internal | 1568 } } // namespace v8::internal |
| 2138 | 1569 |
| 2139 #endif // V8_TARGET_ARCH_A64 | 1570 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |