| 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 |