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 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
821 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx); | 821 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx); |
822 __ j(below_equal, &extra); | 822 __ j(below_equal, &extra); |
823 | 823 |
824 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, | 824 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, |
825 &slow, kCheckMap, kDontIncrementLength); | 825 &slow, kCheckMap, kDontIncrementLength); |
826 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, | 826 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, |
827 &slow, kDontCheckMap, kIncrementLength); | 827 &slow, kDontCheckMap, kIncrementLength); |
828 } | 828 } |
829 | 829 |
830 | 830 |
831 // The generated code does not accept smi keys. | |
832 // The generated code falls through if both probes miss. | |
833 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, | |
834 int argc, | |
835 Code::Kind kind, | |
836 ExtraICState extra_state) { | |
837 // ----------- S t a t e ------------- | |
838 // rcx : function name | |
839 // rdx : receiver | |
840 // ----------------------------------- | |
841 Label number, non_number, non_string, boolean, probe, miss; | |
842 | |
843 // Probe the stub cache. | |
844 Code::Flags flags = Code::ComputeFlags(kind, | |
845 MONOMORPHIC, | |
846 extra_state, | |
847 Code::NORMAL, | |
848 argc); | |
849 masm->isolate()->stub_cache()->GenerateProbe( | |
850 masm, flags, rdx, rcx, rbx, rax); | |
851 | |
852 // If the stub cache probing failed, the receiver might be a value. | |
853 // For value objects, we use the map of the prototype objects for | |
854 // the corresponding JSValue for the cache and that is what we need | |
855 // to probe. | |
856 // | |
857 // Check for number. | |
858 __ JumpIfSmi(rdx, &number); | |
859 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx); | |
860 __ j(not_equal, &non_number); | |
861 __ bind(&number); | |
862 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
863 masm, Context::NUMBER_FUNCTION_INDEX, rdx); | |
864 __ jmp(&probe); | |
865 | |
866 // Check for string. | |
867 __ bind(&non_number); | |
868 __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE); | |
869 __ j(above_equal, &non_string); | |
870 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
871 masm, Context::STRING_FUNCTION_INDEX, rdx); | |
872 __ jmp(&probe); | |
873 | |
874 // Check for boolean. | |
875 __ bind(&non_string); | |
876 __ CompareRoot(rdx, Heap::kTrueValueRootIndex); | |
877 __ j(equal, &boolean); | |
878 __ CompareRoot(rdx, Heap::kFalseValueRootIndex); | |
879 __ j(not_equal, &miss); | |
880 __ bind(&boolean); | |
881 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
882 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); | |
883 | |
884 // Probe the stub cache for the value object. | |
885 __ bind(&probe); | |
886 masm->isolate()->stub_cache()->GenerateProbe( | |
887 masm, flags, rdx, rcx, rbx, no_reg); | |
888 | |
889 __ bind(&miss); | |
890 } | |
891 | |
892 | |
893 static void GenerateFunctionTailCall(MacroAssembler* masm, | |
894 int argc, | |
895 Label* miss) { | |
896 // ----------- S t a t e ------------- | |
897 // rcx : function name | |
898 // rdi : function | |
899 // rsp[0] : return address | |
900 // rsp[8] : argument argc | |
901 // rsp[16] : argument argc - 1 | |
902 // ... | |
903 // rsp[argc * 8] : argument 1 | |
904 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
905 // ----------------------------------- | |
906 __ JumpIfSmi(rdi, miss); | |
907 // Check that the value is a JavaScript function. | |
908 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx); | |
909 __ j(not_equal, miss); | |
910 | |
911 // Invoke the function. | |
912 ParameterCount actual(argc); | |
913 __ InvokeFunction(rdi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
914 } | |
915 | |
916 | |
917 // The generated code falls through if the call should be handled by runtime. | |
918 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { | |
919 // ----------- S t a t e ------------- | |
920 // rcx : function name | |
921 // rsp[0] : return address | |
922 // rsp[8] : argument argc | |
923 // rsp[16] : argument argc - 1 | |
924 // ... | |
925 // rsp[argc * 8] : argument 1 | |
926 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
927 // ----------------------------------- | |
928 Label miss; | |
929 | |
930 StackArgumentsAccessor args(rsp, argc); | |
931 __ movp(rdx, args.GetReceiverOperand()); | |
932 | |
933 GenerateNameDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss); | |
934 | |
935 // rax: elements | |
936 // Search the dictionary placing the result in rdi. | |
937 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi); | |
938 | |
939 GenerateFunctionTailCall(masm, argc, &miss); | |
940 | |
941 __ bind(&miss); | |
942 } | |
943 | |
944 | |
945 void CallICBase::GenerateMiss(MacroAssembler* masm, | |
946 int argc, | |
947 IC::UtilityId id, | |
948 ExtraICState extra_state) { | |
949 // ----------- S t a t e ------------- | |
950 // rcx : function name | |
951 // rsp[0] : return address | |
952 // rsp[8] : argument argc | |
953 // rsp[16] : argument argc - 1 | |
954 // ... | |
955 // rsp[argc * 8] : argument 1 | |
956 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
957 // ----------------------------------- | |
958 | |
959 Counters* counters = masm->isolate()->counters(); | |
960 if (id == IC::kCallIC_Miss) { | |
961 __ IncrementCounter(counters->call_miss(), 1); | |
962 } else { | |
963 __ IncrementCounter(counters->keyed_call_miss(), 1); | |
964 } | |
965 | |
966 StackArgumentsAccessor args(rsp, argc); | |
967 __ movp(rdx, args.GetReceiverOperand()); | |
968 | |
969 // Enter an internal frame. | |
970 { | |
971 FrameScope scope(masm, StackFrame::INTERNAL); | |
972 | |
973 // Push the receiver and the name of the function. | |
974 __ push(rdx); | |
975 __ push(rcx); | |
976 | |
977 // Call the entry. | |
978 CEntryStub stub(1); | |
979 __ Set(rax, 2); | |
980 __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate())); | |
981 __ CallStub(&stub); | |
982 | |
983 // Move result to rdi and exit the internal frame. | |
984 __ movp(rdi, rax); | |
985 } | |
986 | |
987 // Check if the receiver is a global object of some sort. | |
988 // This can happen only for regular CallIC but not KeyedCallIC. | |
989 if (id == IC::kCallIC_Miss) { | |
990 Label invoke, global; | |
991 __ movp(rdx, args.GetReceiverOperand()); | |
992 __ JumpIfSmi(rdx, &invoke); | |
993 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx); | |
994 __ j(equal, &global); | |
995 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE); | |
996 __ j(not_equal, &invoke); | |
997 | |
998 // Patch the receiver on the stack. | |
999 __ bind(&global); | |
1000 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | |
1001 __ movp(args.GetReceiverOperand(), rdx); | |
1002 __ bind(&invoke); | |
1003 } | |
1004 | |
1005 // Invoke the function. | |
1006 ParameterCount actual(argc); | |
1007 __ InvokeFunction(rdi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
1008 } | |
1009 | |
1010 | |
1011 void CallIC::GenerateMegamorphic(MacroAssembler* masm, | |
1012 int argc, | |
1013 ExtraICState extra_ic_state) { | |
1014 // ----------- S t a t e ------------- | |
1015 // rcx : function name | |
1016 // rsp[0] : return address | |
1017 // rsp[8] : argument argc | |
1018 // rsp[16] : argument argc - 1 | |
1019 // ... | |
1020 // rsp[argc * 8] : argument 1 | |
1021 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
1022 // ----------------------------------- | |
1023 | |
1024 StackArgumentsAccessor args(rsp, argc); | |
1025 __ movp(rdx, args.GetReceiverOperand()); | |
1026 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state); | |
1027 GenerateMiss(masm, argc, extra_ic_state); | |
1028 } | |
1029 | |
1030 | |
1031 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | |
1032 // ----------- S t a t e ------------- | |
1033 // rcx : function name | |
1034 // rsp[0] : return address | |
1035 // rsp[8] : argument argc | |
1036 // rsp[16] : argument argc - 1 | |
1037 // ... | |
1038 // rsp[argc * 8] : argument 1 | |
1039 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
1040 // ----------------------------------- | |
1041 | |
1042 StackArgumentsAccessor args(rsp, argc); | |
1043 __ movp(rdx, args.GetReceiverOperand()); | |
1044 | |
1045 Label do_call, slow_call, slow_load; | |
1046 Label check_number_dictionary, check_name, lookup_monomorphic_cache; | |
1047 Label index_smi, index_name; | |
1048 | |
1049 // Check that the key is a smi. | |
1050 __ JumpIfNotSmi(rcx, &check_name); | |
1051 | |
1052 __ bind(&index_smi); | |
1053 // Now the key is known to be a smi. This place is also jumped to from below | |
1054 // where a numeric string is converted to a smi. | |
1055 | |
1056 GenerateKeyedLoadReceiverCheck( | |
1057 masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call); | |
1058 | |
1059 GenerateFastArrayLoad( | |
1060 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load); | |
1061 Counters* counters = masm->isolate()->counters(); | |
1062 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1); | |
1063 | |
1064 __ bind(&do_call); | |
1065 // receiver in rdx is not used after this point. | |
1066 // rcx: key | |
1067 // rdi: function | |
1068 GenerateFunctionTailCall(masm, argc, &slow_call); | |
1069 | |
1070 __ bind(&check_number_dictionary); | |
1071 // rax: elements | |
1072 // rcx: smi key | |
1073 // Check whether the elements is a number dictionary. | |
1074 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | |
1075 Heap::kHashTableMapRootIndex); | |
1076 __ j(not_equal, &slow_load); | |
1077 __ SmiToInteger32(rbx, rcx); | |
1078 // ebx: untagged index | |
1079 __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi); | |
1080 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); | |
1081 __ jmp(&do_call); | |
1082 | |
1083 __ bind(&slow_load); | |
1084 // This branch is taken when calling KeyedCallIC_Miss is neither required | |
1085 // nor beneficial. | |
1086 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); | |
1087 { | |
1088 FrameScope scope(masm, StackFrame::INTERNAL); | |
1089 __ push(rcx); // save the key | |
1090 __ push(rdx); // pass the receiver | |
1091 __ push(rcx); // pass the key | |
1092 __ CallRuntime(Runtime::kKeyedGetProperty, 2); | |
1093 __ pop(rcx); // restore the key | |
1094 } | |
1095 __ movp(rdi, rax); | |
1096 __ jmp(&do_call); | |
1097 | |
1098 __ bind(&check_name); | |
1099 GenerateKeyNameCheck(masm, rcx, rax, rbx, &index_name, &slow_call); | |
1100 | |
1101 // The key is known to be a unique name. | |
1102 // If the receiver is a regular JS object with slow properties then do | |
1103 // a quick inline probe of the receiver's dictionary. | |
1104 // Otherwise do the monomorphic cache probe. | |
1105 GenerateKeyedLoadReceiverCheck( | |
1106 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); | |
1107 | |
1108 __ movp(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset)); | |
1109 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), | |
1110 Heap::kHashTableMapRootIndex); | |
1111 __ j(not_equal, &lookup_monomorphic_cache); | |
1112 | |
1113 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi); | |
1114 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); | |
1115 __ jmp(&do_call); | |
1116 | |
1117 __ bind(&lookup_monomorphic_cache); | |
1118 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); | |
1119 GenerateMonomorphicCacheProbe(masm, | |
1120 argc, | |
1121 Code::KEYED_CALL_IC, | |
1122 kNoExtraICState); | |
1123 // Fall through on miss. | |
1124 | |
1125 __ bind(&slow_call); | |
1126 // This branch is taken if: | |
1127 // - the receiver requires boxing or access check, | |
1128 // - the key is neither smi nor a unique name, | |
1129 // - the value loaded is not a function, | |
1130 // - there is hope that the runtime will create a monomorphic call stub | |
1131 // that will get fetched next time. | |
1132 __ IncrementCounter(counters->keyed_call_generic_slow(), 1); | |
1133 GenerateMiss(masm, argc); | |
1134 | |
1135 __ bind(&index_name); | |
1136 __ IndexFromHash(rbx, rcx); | |
1137 // Now jump to the place where smi keys are handled. | |
1138 __ jmp(&index_smi); | |
1139 } | |
1140 | |
1141 | |
1142 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | |
1143 // ----------- S t a t e ------------- | |
1144 // rcx : function name | |
1145 // rsp[0] : return address | |
1146 // rsp[8] : argument argc | |
1147 // rsp[16] : argument argc - 1 | |
1148 // ... | |
1149 // rsp[argc * 8] : argument 1 | |
1150 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
1151 // ----------------------------------- | |
1152 | |
1153 // Check if the name is really a name. | |
1154 Label miss; | |
1155 __ JumpIfSmi(rcx, &miss); | |
1156 Condition cond = masm->IsObjectNameType(rcx, rax, rax); | |
1157 __ j(NegateCondition(cond), &miss); | |
1158 CallICBase::GenerateNormal(masm, argc); | |
1159 __ bind(&miss); | |
1160 GenerateMiss(masm, argc); | |
1161 } | |
1162 | |
1163 | |
1164 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, | 831 static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm, |
1165 Register object, | 832 Register object, |
1166 Register key, | 833 Register key, |
1167 Register scratch1, | 834 Register scratch1, |
1168 Register scratch2, | 835 Register scratch2, |
1169 Register scratch3, | 836 Register scratch3, |
1170 Label* unmapped_case, | 837 Label* unmapped_case, |
1171 Label* slow_case) { | 838 Label* slow_case) { |
1172 Heap* heap = masm->isolate()->heap(); | 839 Heap* heap = masm->isolate()->heap(); |
1173 | 840 |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1299 r8, | 966 r8, |
1300 kDontSaveFPRegs, | 967 kDontSaveFPRegs, |
1301 EMIT_REMEMBERED_SET, | 968 EMIT_REMEMBERED_SET, |
1302 INLINE_SMI_CHECK); | 969 INLINE_SMI_CHECK); |
1303 __ Ret(); | 970 __ Ret(); |
1304 __ bind(&slow); | 971 __ bind(&slow); |
1305 GenerateMiss(masm); | 972 GenerateMiss(masm); |
1306 } | 973 } |
1307 | 974 |
1308 | 975 |
1309 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, | 976 void LoadIC::GenerateMegamorphic(MacroAssembler* masm, |
1310 int argc) { | 977 ExtraICState extra_state) { |
1311 // ----------- S t a t e ------------- | |
1312 // rcx : function name | |
1313 // rsp[0] : return address | |
1314 // rsp[8] : argument argc | |
1315 // rsp[16] : argument argc - 1 | |
1316 // ... | |
1317 // rsp[argc * 8] : argument 1 | |
1318 // rsp[(argc + 1) * 8] : argument 0 = receiver | |
1319 // ----------------------------------- | |
1320 Label slow, notin; | |
1321 StackArgumentsAccessor args(rsp, argc); | |
1322 __ movp(rdx, args.GetReceiverOperand()); | |
1323 Operand mapped_location = GenerateMappedArgumentsLookup( | |
1324 masm, rdx, rcx, rbx, rax, r8, ¬in, &slow); | |
1325 __ movp(rdi, mapped_location); | |
1326 GenerateFunctionTailCall(masm, argc, &slow); | |
1327 __ bind(¬in); | |
1328 // The unmapped lookup expects that the parameter map is in rbx. | |
1329 Operand unmapped_location = | |
1330 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rax, &slow); | |
1331 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex); | |
1332 __ j(equal, &slow); | |
1333 __ movp(rdi, unmapped_location); | |
1334 GenerateFunctionTailCall(masm, argc, &slow); | |
1335 __ bind(&slow); | |
1336 GenerateMiss(masm, argc); | |
1337 } | |
1338 | |
1339 | |
1340 void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) { | |
1341 // ----------- S t a t e ------------- | 978 // ----------- S t a t e ------------- |
1342 // -- rax : receiver | 979 // -- rax : receiver |
1343 // -- rcx : name | 980 // -- rcx : name |
1344 // -- rsp[0] : return address | 981 // -- rsp[0] : return address |
1345 // ----------------------------------- | 982 // ----------------------------------- |
1346 | 983 |
1347 // Probe the stub cache. | 984 // Probe the stub cache. |
1348 ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode); | |
1349 Code::Flags flags = Code::ComputeFlags( | 985 Code::Flags flags = Code::ComputeFlags( |
1350 Code::HANDLER, MONOMORPHIC, extra_ic_state, | 986 Code::HANDLER, MONOMORPHIC, extra_state, |
1351 Code::NORMAL, Code::LOAD_IC); | 987 Code::NORMAL, Code::LOAD_IC); |
1352 masm->isolate()->stub_cache()->GenerateProbe( | 988 masm->isolate()->stub_cache()->GenerateProbe( |
1353 masm, flags, rax, rcx, rbx, rdx); | 989 masm, flags, rax, rcx, rbx, rdx); |
1354 | 990 |
1355 GenerateMiss(masm); | 991 GenerateMiss(masm); |
1356 } | 992 } |
1357 | 993 |
1358 | 994 |
1359 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 995 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
1360 // ----------- S t a t e ------------- | 996 // ----------- S t a t e ------------- |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1691 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) | 1327 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) |
1692 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 1328 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
1693 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 1329 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
1694 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1330 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1695 } | 1331 } |
1696 | 1332 |
1697 | 1333 |
1698 } } // namespace v8::internal | 1334 } } // namespace v8::internal |
1699 | 1335 |
1700 #endif // V8_TARGET_ARCH_X64 | 1336 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |