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 |