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 929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. | 940 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. |
941 __ j(above_equal, &extra); | 941 __ j(above_equal, &extra); |
942 | 942 |
943 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, | 943 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double, |
944 &slow, kCheckMap, kDontIncrementLength); | 944 &slow, kCheckMap, kDontIncrementLength); |
945 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, | 945 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow, |
946 &slow, kDontCheckMap, kIncrementLength); | 946 &slow, kDontCheckMap, kIncrementLength); |
947 } | 947 } |
948 | 948 |
949 | 949 |
950 // The generated code does not accept smi keys. | 950 void LoadIC::GenerateMegamorphic(MacroAssembler* masm, |
951 // The generated code falls through if both probes miss. | |
952 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm, | |
953 int argc, | |
954 Code::Kind kind, | |
955 ExtraICState extra_state) { | |
956 // ----------- S t a t e ------------- | |
957 // -- ecx : name | |
958 // -- edx : receiver | |
959 // ----------------------------------- | |
960 Label number, non_number, non_string, boolean, probe, miss; | |
961 | |
962 // Probe the stub cache. | |
963 Code::Flags flags = Code::ComputeFlags(kind, | |
964 MONOMORPHIC, | |
965 extra_state, | |
966 Code::NORMAL, | |
967 argc); | |
968 Isolate* isolate = masm->isolate(); | |
969 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax); | |
970 | |
971 // If the stub cache probing failed, the receiver might be a value. | |
972 // For value objects, we use the map of the prototype objects for | |
973 // the corresponding JSValue for the cache and that is what we need | |
974 // to probe. | |
975 // | |
976 // Check for number. | |
977 __ JumpIfSmi(edx, &number); | |
978 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx); | |
979 __ j(not_equal, &non_number); | |
980 __ bind(&number); | |
981 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
982 masm, Context::NUMBER_FUNCTION_INDEX, edx); | |
983 __ jmp(&probe); | |
984 | |
985 // Check for string. | |
986 __ bind(&non_number); | |
987 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE); | |
988 __ j(above_equal, &non_string); | |
989 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
990 masm, Context::STRING_FUNCTION_INDEX, edx); | |
991 __ jmp(&probe); | |
992 | |
993 // Check for boolean. | |
994 __ bind(&non_string); | |
995 __ cmp(edx, isolate->factory()->true_value()); | |
996 __ j(equal, &boolean); | |
997 __ cmp(edx, isolate->factory()->false_value()); | |
998 __ j(not_equal, &miss); | |
999 __ bind(&boolean); | |
1000 StubCompiler::GenerateLoadGlobalFunctionPrototype( | |
1001 masm, Context::BOOLEAN_FUNCTION_INDEX, edx); | |
1002 | |
1003 // Probe the stub cache for the value object. | |
1004 __ bind(&probe); | |
1005 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg); | |
1006 __ bind(&miss); | |
1007 } | |
1008 | |
1009 | |
1010 static void GenerateFunctionTailCall(MacroAssembler* masm, | |
1011 int argc, | |
1012 Label* miss) { | |
1013 // ----------- S t a t e ------------- | |
1014 // -- ecx : name | |
1015 // -- edi : function | |
1016 // -- esp[0] : return address | |
1017 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1018 // -- ... | |
1019 // -- esp[(argc + 1) * 4] : receiver | |
1020 // ----------------------------------- | |
1021 | |
1022 // Check that the result is not a smi. | |
1023 __ JumpIfSmi(edi, miss); | |
1024 | |
1025 // Check that the value is a JavaScript function, fetching its map into eax. | |
1026 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | |
1027 __ j(not_equal, miss); | |
1028 | |
1029 // Invoke the function. | |
1030 ParameterCount actual(argc); | |
1031 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
1032 } | |
1033 | |
1034 | |
1035 // The generated code falls through if the call should be handled by runtime. | |
1036 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) { | |
1037 // ----------- S t a t e ------------- | |
1038 // -- ecx : name | |
1039 // -- esp[0] : return address | |
1040 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1041 // -- ... | |
1042 // -- esp[(argc + 1) * 4] : receiver | |
1043 // ----------------------------------- | |
1044 Label miss; | |
1045 | |
1046 // Get the receiver of the function from the stack; 1 ~ return address. | |
1047 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1048 | |
1049 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss); | |
1050 | |
1051 // eax: elements | |
1052 // Search the dictionary placing the result in edi. | |
1053 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi); | |
1054 GenerateFunctionTailCall(masm, argc, &miss); | |
1055 | |
1056 __ bind(&miss); | |
1057 } | |
1058 | |
1059 | |
1060 void CallICBase::GenerateMiss(MacroAssembler* masm, | |
1061 int argc, | |
1062 IC::UtilityId id, | |
1063 ExtraICState extra_state) { | |
1064 // ----------- S t a t e ------------- | |
1065 // -- ecx : name | |
1066 // -- esp[0] : return address | |
1067 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1068 // -- ... | |
1069 // -- esp[(argc + 1) * 4] : receiver | |
1070 // ----------------------------------- | |
1071 | |
1072 Counters* counters = masm->isolate()->counters(); | |
1073 if (id == IC::kCallIC_Miss) { | |
1074 __ IncrementCounter(counters->call_miss(), 1); | |
1075 } else { | |
1076 __ IncrementCounter(counters->keyed_call_miss(), 1); | |
1077 } | |
1078 | |
1079 // Get the receiver of the function from the stack; 1 ~ return address. | |
1080 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1081 | |
1082 { | |
1083 FrameScope scope(masm, StackFrame::INTERNAL); | |
1084 | |
1085 // Push the receiver and the name of the function. | |
1086 __ push(edx); | |
1087 __ push(ecx); | |
1088 | |
1089 // Call the entry. | |
1090 CEntryStub stub(1); | |
1091 __ mov(eax, Immediate(2)); | |
1092 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate()))); | |
1093 __ CallStub(&stub); | |
1094 | |
1095 // Move result to edi and exit the internal frame. | |
1096 __ mov(edi, eax); | |
1097 } | |
1098 | |
1099 // Check if the receiver is a global object of some sort. | |
1100 // This can happen only for regular CallIC but not KeyedCallIC. | |
1101 if (id == IC::kCallIC_Miss) { | |
1102 Label invoke, global; | |
1103 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver | |
1104 __ JumpIfSmi(edx, &invoke, Label::kNear); | |
1105 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | |
1106 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | |
1107 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE); | |
1108 __ j(equal, &global, Label::kNear); | |
1109 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE); | |
1110 __ j(not_equal, &invoke, Label::kNear); | |
1111 | |
1112 // Patch the receiver on the stack. | |
1113 __ bind(&global); | |
1114 __ mov(Operand(esp, (argc + 1) * kPointerSize), | |
1115 masm->isolate()->factory()->undefined_value()); | |
1116 | |
1117 __ bind(&invoke); | |
1118 } | |
1119 | |
1120 // Invoke the function. | |
1121 ParameterCount actual(argc); | |
1122 __ InvokeFunction(edi, actual, JUMP_FUNCTION, NullCallWrapper()); | |
1123 } | |
1124 | |
1125 | |
1126 void CallIC::GenerateMegamorphic(MacroAssembler* masm, | |
1127 int argc, | |
1128 ExtraICState extra_state) { | 951 ExtraICState extra_state) { |
1129 // ----------- S t a t e ------------- | 952 // ----------- S t a t e ------------- |
1130 // -- ecx : name | |
1131 // -- esp[0] : return address | |
1132 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1133 // -- ... | |
1134 // -- esp[(argc + 1) * 4] : receiver | |
1135 // ----------------------------------- | |
1136 | |
1137 // Get the receiver of the function from the stack; 1 ~ return address. | |
1138 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1139 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, | |
1140 extra_state); | |
1141 | |
1142 GenerateMiss(masm, argc, extra_state); | |
1143 } | |
1144 | |
1145 | |
1146 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { | |
1147 // ----------- S t a t e ------------- | |
1148 // -- ecx : name | |
1149 // -- esp[0] : return address | |
1150 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1151 // -- ... | |
1152 // -- esp[(argc + 1) * 4] : receiver | |
1153 // ----------------------------------- | |
1154 | |
1155 // Get the receiver of the function from the stack; 1 ~ return address. | |
1156 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1157 | |
1158 Label do_call, slow_call, slow_load, slow_reload_receiver; | |
1159 Label check_number_dictionary, check_name, lookup_monomorphic_cache; | |
1160 Label index_smi, index_name; | |
1161 | |
1162 // Check that the key is a smi. | |
1163 __ JumpIfNotSmi(ecx, &check_name); | |
1164 | |
1165 __ bind(&index_smi); | |
1166 // Now the key is known to be a smi. This place is also jumped to from | |
1167 // where a numeric string is converted to a smi. | |
1168 | |
1169 GenerateKeyedLoadReceiverCheck( | |
1170 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call); | |
1171 | |
1172 GenerateFastArrayLoad( | |
1173 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load); | |
1174 Isolate* isolate = masm->isolate(); | |
1175 Counters* counters = isolate->counters(); | |
1176 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1); | |
1177 | |
1178 __ bind(&do_call); | |
1179 // receiver in edx is not used after this point. | |
1180 // ecx: key | |
1181 // edi: function | |
1182 GenerateFunctionTailCall(masm, argc, &slow_call); | |
1183 | |
1184 __ bind(&check_number_dictionary); | |
1185 // eax: elements | |
1186 // ecx: smi key | |
1187 // Check whether the elements is a number dictionary. | |
1188 __ CheckMap(eax, | |
1189 isolate->factory()->hash_table_map(), | |
1190 &slow_load, | |
1191 DONT_DO_SMI_CHECK); | |
1192 __ mov(ebx, ecx); | |
1193 __ SmiUntag(ebx); | |
1194 // ebx: untagged index | |
1195 // Receiver in edx will be clobbered, need to reload it on miss. | |
1196 __ LoadFromNumberDictionary( | |
1197 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi); | |
1198 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1); | |
1199 __ jmp(&do_call); | |
1200 | |
1201 __ bind(&slow_reload_receiver); | |
1202 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1203 | |
1204 __ bind(&slow_load); | |
1205 // This branch is taken when calling KeyedCallIC_Miss is neither required | |
1206 // nor beneficial. | |
1207 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1); | |
1208 | |
1209 { | |
1210 FrameScope scope(masm, StackFrame::INTERNAL); | |
1211 __ push(ecx); // save the key | |
1212 __ push(edx); // pass the receiver | |
1213 __ push(ecx); // pass the key | |
1214 __ CallRuntime(Runtime::kKeyedGetProperty, 2); | |
1215 __ pop(ecx); // restore the key | |
1216 // Leave the internal frame. | |
1217 } | |
1218 | |
1219 __ mov(edi, eax); | |
1220 __ jmp(&do_call); | |
1221 | |
1222 __ bind(&check_name); | |
1223 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call); | |
1224 | |
1225 // The key is known to be a unique name. | |
1226 // If the receiver is a regular JS object with slow properties then do | |
1227 // a quick inline probe of the receiver's dictionary. | |
1228 // Otherwise do the monomorphic cache probe. | |
1229 GenerateKeyedLoadReceiverCheck( | |
1230 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache); | |
1231 | |
1232 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset)); | |
1233 __ CheckMap(ebx, | |
1234 isolate->factory()->hash_table_map(), | |
1235 &lookup_monomorphic_cache, | |
1236 DONT_DO_SMI_CHECK); | |
1237 | |
1238 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi); | |
1239 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1); | |
1240 __ jmp(&do_call); | |
1241 | |
1242 __ bind(&lookup_monomorphic_cache); | |
1243 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1); | |
1244 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC, | |
1245 kNoExtraICState); | |
1246 // Fall through on miss. | |
1247 | |
1248 __ bind(&slow_call); | |
1249 // This branch is taken if: | |
1250 // - the receiver requires boxing or access check, | |
1251 // - the key is neither smi nor a unique name, | |
1252 // - the value loaded is not a function, | |
1253 // - there is hope that the runtime will create a monomorphic call stub | |
1254 // that will get fetched next time. | |
1255 __ IncrementCounter(counters->keyed_call_generic_slow(), 1); | |
1256 GenerateMiss(masm, argc); | |
1257 | |
1258 __ bind(&index_name); | |
1259 __ IndexFromHash(ebx, ecx); | |
1260 // Now jump to the place where smi keys are handled. | |
1261 __ jmp(&index_smi); | |
1262 } | |
1263 | |
1264 | |
1265 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm, | |
1266 int argc) { | |
1267 // ----------- S t a t e ------------- | |
1268 // -- ecx : name | |
1269 // -- esp[0] : return address | |
1270 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1271 // -- ... | |
1272 // -- esp[(argc + 1) * 4] : receiver | |
1273 // ----------------------------------- | |
1274 Label slow, notin; | |
1275 Factory* factory = masm->isolate()->factory(); | |
1276 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | |
1277 Operand mapped_location = | |
1278 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, ¬in, &slow); | |
1279 __ mov(edi, mapped_location); | |
1280 GenerateFunctionTailCall(masm, argc, &slow); | |
1281 __ bind(¬in); | |
1282 // The unmapped lookup expects that the parameter map is in ebx. | |
1283 Operand unmapped_location = | |
1284 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow); | |
1285 __ cmp(unmapped_location, factory->the_hole_value()); | |
1286 __ j(equal, &slow); | |
1287 __ mov(edi, unmapped_location); | |
1288 GenerateFunctionTailCall(masm, argc, &slow); | |
1289 __ bind(&slow); | |
1290 GenerateMiss(masm, argc); | |
1291 } | |
1292 | |
1293 | |
1294 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) { | |
1295 // ----------- S t a t e ------------- | |
1296 // -- ecx : name | |
1297 // -- esp[0] : return address | |
1298 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | |
1299 // -- ... | |
1300 // -- esp[(argc + 1) * 4] : receiver | |
1301 // ----------------------------------- | |
1302 | |
1303 // Check if the name is really a name. | |
1304 Label miss; | |
1305 __ JumpIfSmi(ecx, &miss); | |
1306 Condition cond = masm->IsObjectNameType(ecx, eax, eax); | |
1307 __ j(NegateCondition(cond), &miss); | |
1308 CallICBase::GenerateNormal(masm, argc); | |
1309 __ bind(&miss); | |
1310 GenerateMiss(masm, argc); | |
1311 } | |
1312 | |
1313 | |
1314 void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) { | |
1315 // ----------- S t a t e ------------- | |
1316 // -- ecx : name | 953 // -- ecx : name |
1317 // -- edx : receiver | 954 // -- edx : receiver |
1318 // -- esp[0] : return address | 955 // -- esp[0] : return address |
1319 // ----------------------------------- | 956 // ----------------------------------- |
1320 | 957 |
1321 // Probe the stub cache. | 958 // Probe the stub cache. |
1322 ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode); | |
1323 Code::Flags flags = Code::ComputeFlags( | 959 Code::Flags flags = Code::ComputeFlags( |
1324 Code::HANDLER, MONOMORPHIC, extra_ic_state, | 960 Code::HANDLER, MONOMORPHIC, extra_state, |
1325 Code::NORMAL, Code::LOAD_IC); | 961 Code::NORMAL, Code::LOAD_IC); |
1326 masm->isolate()->stub_cache()->GenerateProbe( | 962 masm->isolate()->stub_cache()->GenerateProbe( |
1327 masm, flags, edx, ecx, ebx, eax); | 963 masm, flags, edx, ecx, ebx, eax); |
1328 | 964 |
1329 // Cache miss: Jump to runtime. | 965 // Cache miss: Jump to runtime. |
1330 GenerateMiss(masm); | 966 GenerateMiss(masm); |
1331 } | 967 } |
1332 | 968 |
1333 | 969 |
1334 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 970 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1670 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) | 1306 Condition cc = (check == ENABLE_INLINED_SMI_CHECK) |
1671 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 1307 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
1672 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 1308 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
1673 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 1309 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
1674 } | 1310 } |
1675 | 1311 |
1676 | 1312 |
1677 } } // namespace v8::internal | 1313 } } // namespace v8::internal |
1678 | 1314 |
1679 #endif // V8_TARGET_ARCH_IA32 | 1315 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |