OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
(...skipping 1241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1252 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid))); | 1252 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid))); |
1253 __ cmpl(Address(EBX, 0 * kWordSize), imm_smi_cid); | 1253 __ cmpl(Address(EBX, 0 * kWordSize), imm_smi_cid); |
1254 __ j(NOT_EQUAL, &error, Assembler::kNearJump); | 1254 __ j(NOT_EQUAL, &error, Assembler::kNearJump); |
1255 __ cmpl(Address(EBX, 1 * kWordSize), imm_smi_cid); | 1255 __ cmpl(Address(EBX, 1 * kWordSize), imm_smi_cid); |
1256 __ j(EQUAL, &ok, Assembler::kNearJump); | 1256 __ j(EQUAL, &ok, Assembler::kNearJump); |
1257 __ Bind(&error); | 1257 __ Bind(&error); |
1258 __ Stop("Incorrect IC data"); | 1258 __ Stop("Incorrect IC data"); |
1259 __ Bind(&ok); | 1259 __ Bind(&ok); |
1260 #endif | 1260 #endif |
1261 if (FLAG_optimization_counter_threshold >= 0) { | 1261 if (FLAG_optimization_counter_threshold >= 0) { |
| 1262 // Update counter. |
1262 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1263 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
1263 // Update counter, ignore overflow. | 1264 __ movl(ECX, Address(EBX, count_offset)); |
1264 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1))); | 1265 __ addl(ECX, Immediate(Smi::RawValue(1))); |
| 1266 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue))); |
| 1267 __ cmovno(EDI, ECX); |
| 1268 __ StoreIntoSmiField(Address(EBX, count_offset), EDI); |
1265 } | 1269 } |
1266 __ ret(); | 1270 __ ret(); |
1267 } | 1271 } |
1268 | 1272 |
1269 | 1273 |
1270 // Generate inline cache check for 'num_args'. | 1274 // Generate inline cache check for 'num_args'. |
1271 // ECX: Inline cache data object. | 1275 // ECX: Inline cache data object. |
1272 // TOS(0): return address | 1276 // TOS(0): return address |
1273 // Control flow: | 1277 // Control flow: |
1274 // - If receiver is null -> jump to IC miss. | 1278 // - If receiver is null -> jump to IC miss. |
1275 // - If receiver is Smi -> load Smi class. | 1279 // - If receiver is Smi -> load Smi class. |
1276 // - If receiver is not-Smi -> load receiver's class. | 1280 // - If receiver is not-Smi -> load receiver's class. |
1277 // - Check if 'num_args' (including receiver) match any IC data group. | 1281 // - Check if 'num_args' (including receiver) match any IC data group. |
1278 // - Match found -> jump to target. | 1282 // - Match found -> jump to target. |
1279 // - Match not found -> jump to IC miss. | 1283 // - Match not found -> jump to IC miss. |
1280 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1284 void StubCode::GenerateNArgsCheckInlineCacheStub( |
1281 Assembler* assembler, | 1285 Assembler* assembler, |
1282 intptr_t num_args, | 1286 intptr_t num_args, |
1283 const RuntimeEntry& handle_ic_miss, | 1287 const RuntimeEntry& handle_ic_miss, |
1284 Token::Kind kind, | 1288 Token::Kind kind, |
1285 bool optimized) { | 1289 bool optimized) { |
1286 ASSERT(num_args == 1 || num_args == 2); | 1290 ASSERT(num_args > 0); |
1287 #if defined(DEBUG) | 1291 #if defined(DEBUG) |
1288 { | 1292 { |
1289 Label ok; | 1293 Label ok; |
1290 // Check that the IC data array has NumArgsTested() == num_args. | 1294 // Check that the IC data array has NumArgsTested() == num_args. |
1291 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1295 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
1292 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset())); | 1296 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset())); |
1293 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1297 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
1294 __ andl(EBX, Immediate(ICData::NumArgsTestedMask())); | 1298 __ andl(EBX, Immediate(ICData::NumArgsTestedMask())); |
1295 __ cmpl(EBX, Immediate(num_args)); | 1299 __ cmpl(EBX, Immediate(num_args)); |
1296 __ j(EQUAL, &ok, Assembler::kNearJump); | 1300 __ j(EQUAL, &ok, Assembler::kNearJump); |
(...skipping 14 matching lines...) Expand all Loading... |
1311 if (kind != Token::kILLEGAL) { | 1315 if (kind != Token::kILLEGAL) { |
1312 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | 1316 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
1313 } | 1317 } |
1314 __ Bind(¬_smi_or_overflow); | 1318 __ Bind(¬_smi_or_overflow); |
1315 | 1319 |
1316 __ Comment("Extract ICData initial values and receiver cid"); | 1320 __ Comment("Extract ICData initial values and receiver cid"); |
1317 // ECX: IC data object (preserved). | 1321 // ECX: IC data object (preserved). |
1318 // Load arguments descriptor into EDX. | 1322 // Load arguments descriptor into EDX. |
1319 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); | 1323 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); |
1320 // Loop that checks if there is an IC data match. | 1324 // Loop that checks if there is an IC data match. |
1321 Label loop, found, miss; | |
1322 // ECX: IC data object (preserved). | 1325 // ECX: IC data object (preserved). |
1323 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); | 1326 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); |
1324 // EBX: ic_data_array with check entries: classes and target functions. | 1327 // EBX: ic_data_array with check entries: classes and target functions. |
1325 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); | 1328 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); |
1326 // EBX: points directly to the first ic data array element. | 1329 // EBX: points directly to the first ic data array element. |
1327 | 1330 |
1328 // Get argument descriptor into EAX. In the 1-argument case this is the | 1331 // Get the receiver's class ID (first read number of arguments from |
1329 // last time we need the argument descriptor, and we reuse EAX for the | 1332 // arguments descriptor array and then access the receiver from the stack). |
1330 // class IDs from the IC descriptor. In the 2-argument case we preserve | |
1331 // the argument descriptor in EAX. | |
1332 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); | 1333 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
1333 if (num_args == 1) { | 1334 __ movl(EDI, Address(ESP, EAX, TIMES_2, 0)); // EAX (argument_count) is smi. |
1334 // Load first argument into EDI. | 1335 __ LoadTaggedClassIdMayBeSmi(EAX, EDI); |
1335 __ movl(EDI, | 1336 |
1336 Address(ESP, EAX, TIMES_2, 0)); // EAX (argument count) is Smi. | 1337 // EAX: receiver's class ID (smi). |
| 1338 __ movl(EDI, Address(EBX, 0)); // First class id (smi) to check. |
| 1339 Label loop, update, test, found; |
| 1340 __ jmp(&test); |
| 1341 |
| 1342 __ Comment("ICData loop"); |
| 1343 __ Bind(&loop); |
| 1344 for (int i = 0; i < num_args; i++) { |
| 1345 if (i > 0) { |
| 1346 // If not the first, load the next argument's class ID. |
| 1347 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 1348 __ movl(EDI, Address(ESP, EAX, TIMES_2, -i * kWordSize)); |
| 1349 __ LoadTaggedClassIdMayBeSmi(EAX, EDI); |
| 1350 |
| 1351 // EAX: next argument class ID (smi). |
| 1352 __ movl(EDI, Address(EBX, i * kWordSize)); |
| 1353 // EDI: next class ID to check (smi). |
| 1354 } |
| 1355 __ cmpl(EAX, EDI); // Class id match? |
| 1356 if (i < (num_args - 1)) { |
| 1357 __ j(NOT_EQUAL, &update); // Continue. |
| 1358 } else { |
| 1359 // Last check, all checks before matched. |
| 1360 __ j(EQUAL, &found); // Break. |
| 1361 } |
| 1362 } |
| 1363 __ Bind(&update); |
| 1364 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 1365 if (num_args > 1) { |
| 1366 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
| 1367 __ movl(EDI, Address(ESP, EAX, TIMES_2, 0)); |
1337 __ LoadTaggedClassIdMayBeSmi(EAX, EDI); | 1368 __ LoadTaggedClassIdMayBeSmi(EAX, EDI); |
1338 // EAX: first argument class ID as Smi. | |
1339 __ movl(EDI, Address(EBX, 0)); | |
1340 } | 1369 } |
1341 | 1370 |
1342 __ Comment("ICData loop"); | 1371 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 1372 __ addl(EBX, Immediate(entry_size)); // Next entry. |
| 1373 __ movl(EDI, Address(EBX, 0)); // Next class ID. |
1343 | 1374 |
1344 // We unroll the generic one that is generated once more than the others. | 1375 __ Bind(&test); |
1345 bool optimize = kind == Token::kILLEGAL; | 1376 __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid))); // Done? |
1346 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1377 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
1347 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | |
1348 | 1378 |
1349 __ Bind(&loop); | |
1350 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) { | |
1351 Label update; | |
1352 for (int i = 0; i < num_args; i++) { | |
1353 if (num_args == 2) { | |
1354 // Load ith argument into EDI. | |
1355 __ movl(EDI, Address(ESP, EAX, TIMES_2, -kWordSize * i)); | |
1356 __ LoadTaggedClassIdMayBeSmi(EDI, EDI); | |
1357 // EDI: ith argument class ID (smi). | |
1358 __ cmpl(EDI, Address(EBX, kWordSize * i)); // Class id match? | |
1359 } else { | |
1360 __ cmpl(EDI, EAX); // Class id match? | |
1361 } | |
1362 if (i < (num_args - 1)) { | |
1363 __ j(NOT_EQUAL, &update); // Continue. | |
1364 } else { | |
1365 // Last check, all checks before matched. | |
1366 __ j(EQUAL, &found); // Break. | |
1367 } | |
1368 } | |
1369 __ Bind(&update); | |
1370 | |
1371 const intptr_t entry_size = | |
1372 ICData::TestEntryLengthFor(num_args) * kWordSize; | |
1373 __ addl(EBX, Immediate(entry_size)); // Next entry. | |
1374 if (num_args == 2) { | |
1375 __ cmpl(Address(EBX, -entry_size), | |
1376 Immediate(Smi::RawValue(kIllegalCid))); // Done? | |
1377 } else { | |
1378 __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid))); // Done? | |
1379 __ movl(EDI, Address(EBX, 0)); | |
1380 } | |
1381 if (unroll == 0) { | |
1382 __ j(NOT_EQUAL, &loop); | |
1383 } else { | |
1384 __ j(EQUAL, &miss); | |
1385 } | |
1386 } | |
1387 | |
1388 __ Bind(&miss); | |
1389 __ Comment("IC miss"); | 1379 __ Comment("IC miss"); |
1390 // Compute address of arguments (first read number of arguments from | 1380 // Compute address of arguments (first read number of arguments from |
1391 // arguments descriptor array and then compute address on the stack). | 1381 // arguments descriptor array and then compute address on the stack). |
1392 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); | 1382 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); |
1393 __ leal(EAX, Address(ESP, EAX, TIMES_2, 0)); // EAX is Smi. | 1383 __ leal(EAX, Address(ESP, EAX, TIMES_2, 0)); // EAX is Smi. |
1394 // Create a stub frame as we are pushing some objects on the stack before | 1384 // Create a stub frame as we are pushing some objects on the stack before |
1395 // calling into the runtime. | 1385 // calling into the runtime. |
1396 __ EnterStubFrame(); | 1386 __ EnterStubFrame(); |
1397 __ pushl(EDX); // Preserve arguments descriptor array. | 1387 __ pushl(EDX); // Preserve arguments descriptor array. |
1398 __ pushl(ECX); // Preserve IC data object. | 1388 __ pushl(ECX); // Preserve IC data object. |
(...skipping 16 matching lines...) Expand all Loading... |
1415 Label call_target_function; | 1405 Label call_target_function; |
1416 if (!FLAG_lazy_dispatchers) { | 1406 if (!FLAG_lazy_dispatchers) { |
1417 GenerateDispatcherCode(assembler, &call_target_function); | 1407 GenerateDispatcherCode(assembler, &call_target_function); |
1418 } else { | 1408 } else { |
1419 __ jmp(&call_target_function); | 1409 __ jmp(&call_target_function); |
1420 } | 1410 } |
1421 | 1411 |
1422 __ Bind(&found); | 1412 __ Bind(&found); |
1423 | 1413 |
1424 // EBX: Pointer to an IC data check group. | 1414 // EBX: Pointer to an IC data check group. |
| 1415 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 1416 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
1425 if (FLAG_optimization_counter_threshold >= 0) { | 1417 if (FLAG_optimization_counter_threshold >= 0) { |
1426 __ Comment("Update caller's counter"); | 1418 __ Comment("Update caller's counter"); |
1427 // Ignore overflow. | 1419 __ movl(EAX, Address(EBX, count_offset)); |
1428 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1))); | 1420 __ addl(EAX, Immediate(Smi::RawValue(1))); |
| 1421 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue))); |
| 1422 __ cmovno(EDI, EAX); |
| 1423 __ StoreIntoSmiField(Address(EBX, count_offset), EDI); |
1429 } | 1424 } |
1430 | 1425 |
1431 __ movl(EAX, Address(EBX, target_offset)); | 1426 __ movl(EAX, Address(EBX, target_offset)); |
1432 __ Bind(&call_target_function); | 1427 __ Bind(&call_target_function); |
1433 __ Comment("Call target"); | 1428 __ Comment("Call target"); |
1434 // EAX: Target function. | 1429 // EAX: Target function. |
1435 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset())); | 1430 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset())); |
1436 __ jmp(EBX); | 1431 __ jmp(EBX); |
1437 | 1432 |
1438 if (FLAG_support_debugger && !optimized) { | 1433 if (FLAG_support_debugger && !optimized) { |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1553 | 1548 |
1554 // ECX: IC data object (preserved). | 1549 // ECX: IC data object (preserved). |
1555 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); | 1550 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); |
1556 // EBX: ic_data_array with entries: target functions and count. | 1551 // EBX: ic_data_array with entries: target functions and count. |
1557 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); | 1552 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); |
1558 // EBX: points directly to the first ic data array element. | 1553 // EBX: points directly to the first ic data array element. |
1559 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; | 1554 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; |
1560 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; | 1555 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; |
1561 | 1556 |
1562 if (FLAG_optimization_counter_threshold >= 0) { | 1557 if (FLAG_optimization_counter_threshold >= 0) { |
1563 // Increment count for this call, ignore overflow. | 1558 // Increment count for this call. |
1564 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1))); | 1559 __ movl(EAX, Address(EBX, count_offset)); |
| 1560 __ addl(EAX, Immediate(Smi::RawValue(1))); |
| 1561 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue))); |
| 1562 __ cmovno(EDI, EAX); |
| 1563 __ StoreIntoSmiField(Address(EBX, count_offset), EDI); |
1565 } | 1564 } |
1566 | 1565 |
1567 // Load arguments descriptor into EDX. | 1566 // Load arguments descriptor into EDX. |
1568 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); | 1567 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); |
1569 | 1568 |
1570 // Get function and call it, if possible. | 1569 // Get function and call it, if possible. |
1571 __ movl(EAX, Address(EBX, target_offset)); | 1570 __ movl(EAX, Address(EBX, target_offset)); |
1572 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset())); | 1571 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset())); |
1573 __ jmp(EBX); | 1572 __ jmp(EBX); |
1574 | 1573 |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2088 } | 2087 } |
2089 | 2088 |
2090 | 2089 |
2091 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2090 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
2092 __ int3(); | 2091 __ int3(); |
2093 } | 2092 } |
2094 | 2093 |
2095 } // namespace dart | 2094 } // namespace dart |
2096 | 2095 |
2097 #endif // defined TARGET_ARCH_IA32 | 2096 #endif // defined TARGET_ARCH_IA32 |
OLD | NEW |