Chromium Code Reviews| 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 1244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1255 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1255 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1256 Register temp_reg) { | 1256 Register temp_reg) { |
| 1257 Register ic_reg = ECX; | 1257 Register ic_reg = ECX; |
| 1258 Register func_reg = temp_reg; | 1258 Register func_reg = temp_reg; |
| 1259 ASSERT(ic_reg != func_reg); | 1259 ASSERT(ic_reg != func_reg); |
| 1260 __ movl(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); | 1260 __ movl(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); |
| 1261 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); | 1261 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1262 } | 1262 } |
| 1263 | 1263 |
| 1264 | 1264 |
| 1265 // Note: ECX must be preserved. | |
| 1266 // Attempt a quick Smi operation for known operations ('kind'). The ICData | |
| 1267 // must have been primed with a Smi/Smi check that will be used for counting | |
| 1268 // the invocations. | |
| 1269 static void EmitFastSmiOp(Assembler* assembler, | |
| 1270 Token::Kind kind, | |
| 1271 intptr_t num_args, | |
| 1272 Label* not_smi_or_overflow) { | |
| 1273 ASSERT(num_args == 2); | |
| 1274 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Right | |
| 1275 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left | |
| 1276 __ movl(EBX, EDI); | |
| 1277 __ orl(EBX, EAX); | |
| 1278 __ testl(EBX, Immediate(kSmiTagMask)); | |
| 1279 __ j(NOT_ZERO, not_smi_or_overflow, Assembler::kNearJump); | |
| 1280 switch (kind) { | |
| 1281 case Token::kADD: { | |
| 1282 __ addl(EAX, EDI); | |
| 1283 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump); | |
| 1284 break; | |
| 1285 } | |
| 1286 case Token::kSUB: { | |
| 1287 __ subl(EAX, EDI); | |
| 1288 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump); | |
| 1289 break; | |
| 1290 } | |
| 1291 case Token::kEQ: { | |
| 1292 Label done, is_true; | |
| 1293 __ cmpl(EAX, EDI); | |
| 1294 __ j(EQUAL, &is_true, Assembler::kNearJump); | |
| 1295 __ LoadObject(EAX, Bool::False()); | |
| 1296 __ jmp(&done, Assembler::kNearJump); | |
| 1297 __ Bind(&is_true); | |
| 1298 __ LoadObject(EAX, Bool::True()); | |
| 1299 __ Bind(&done); | |
| 1300 break; | |
| 1301 } | |
| 1302 default: UNIMPLEMENTED(); | |
| 1303 } | |
| 1304 | |
| 1305 // ECX: IC data object. | |
| 1306 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); | |
| 1307 // EBX: ic_data_array with check entries: classes and target functions. | |
| 1308 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); | |
| 1309 #ifdef DEBUG | |
| 1310 // Check that first entry is for Smi/Smi. | |
| 1311 Label error, ok; | |
| 1312 const Immediate& imm_smi_cid = | |
| 1313 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid))); | |
| 1314 __ cmpl(Address(EBX, 0 * kWordSize), imm_smi_cid); | |
| 1315 __ j(NOT_EQUAL, &error, Assembler::kNearJump); | |
| 1316 __ cmpl(Address(EBX, 1 * kWordSize), imm_smi_cid); | |
| 1317 __ j(EQUAL, &ok, Assembler::kNearJump); | |
| 1318 __ Bind(&error); | |
|
zra
2014/08/15 21:45:08
Same comment as on ARM.
| |
| 1319 __ Stop("Incorrect IC data"); | |
| 1320 __ Bind(&ok); | |
| 1321 #endif | |
| 1322 // Update counter. | |
| 1323 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | |
| 1324 __ movl(ECX, Address(EBX, count_offset)); | |
| 1325 __ addl(ECX, Immediate(Smi::RawValue(1))); | |
| 1326 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue))); | |
| 1327 __ cmovno(EDI, ECX); | |
| 1328 __ movl(Address(EBX, count_offset), EDI); | |
| 1329 | |
| 1330 __ ret(); | |
| 1331 } | |
| 1332 | |
| 1333 | |
| 1265 // Generate inline cache check for 'num_args'. | 1334 // Generate inline cache check for 'num_args'. |
| 1266 // ECX: Inline cache data object. | 1335 // ECX: Inline cache data object. |
| 1267 // TOS(0): return address | 1336 // TOS(0): return address |
| 1268 // Control flow: | 1337 // Control flow: |
| 1269 // - If receiver is null -> jump to IC miss. | 1338 // - If receiver is null -> jump to IC miss. |
| 1270 // - If receiver is Smi -> load Smi class. | 1339 // - If receiver is Smi -> load Smi class. |
| 1271 // - If receiver is not-Smi -> load receiver's class. | 1340 // - If receiver is not-Smi -> load receiver's class. |
| 1272 // - Check if 'num_args' (including receiver) match any IC data group. | 1341 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1273 // - Match found -> jump to target. | 1342 // - Match found -> jump to target. |
| 1274 // - Match not found -> jump to IC miss. | 1343 // - Match not found -> jump to IC miss. |
| 1275 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1344 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1276 Assembler* assembler, | 1345 Assembler* assembler, |
| 1277 intptr_t num_args, | 1346 intptr_t num_args, |
| 1278 const RuntimeEntry& handle_ic_miss) { | 1347 const RuntimeEntry& handle_ic_miss, |
| 1348 Token::Kind kind) { | |
| 1279 ASSERT(num_args > 0); | 1349 ASSERT(num_args > 0); |
| 1280 #if defined(DEBUG) | 1350 #if defined(DEBUG) |
| 1281 { Label ok; | 1351 { Label ok; |
| 1282 // Check that the IC data array has NumArgsTested() == num_args. | 1352 // Check that the IC data array has NumArgsTested() == num_args. |
| 1283 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1353 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1284 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset())); | 1354 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset())); |
| 1285 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1355 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1286 __ andl(EBX, Immediate(ICData::NumArgsTestedMask())); | 1356 __ andl(EBX, Immediate(ICData::NumArgsTestedMask())); |
| 1287 __ cmpl(EBX, Immediate(num_args)); | 1357 __ cmpl(EBX, Immediate(num_args)); |
| 1288 __ j(EQUAL, &ok, Assembler::kNearJump); | 1358 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1289 __ Stop("Incorrect stub for IC data"); | 1359 __ Stop("Incorrect stub for IC data"); |
| 1290 __ Bind(&ok); | 1360 __ Bind(&ok); |
| 1291 } | 1361 } |
| 1292 #endif // DEBUG | 1362 #endif // DEBUG |
| 1293 | 1363 |
| 1294 Label stepping, done_stepping; | 1364 Label stepping, done_stepping; |
| 1295 // Check single stepping. | 1365 // Check single stepping. |
| 1296 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); | 1366 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); |
| 1297 __ cmpb(Address(EAX, Isolate::single_step_offset()), Immediate(0)); | 1367 __ cmpb(Address(EAX, Isolate::single_step_offset()), Immediate(0)); |
| 1298 __ j(NOT_EQUAL, &stepping); | 1368 __ j(NOT_EQUAL, &stepping); |
| 1299 __ Bind(&done_stepping); | 1369 __ Bind(&done_stepping); |
| 1300 | 1370 |
| 1371 if (kind != Token::kILLEGAL) { | |
| 1372 Label not_smi_or_overflow; | |
| 1373 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | |
| 1374 __ Bind(¬_smi_or_overflow); | |
| 1375 } | |
| 1376 | |
| 1301 // ECX: IC data object (preserved). | 1377 // ECX: IC data object (preserved). |
| 1302 // Load arguments descriptor into EDX. | 1378 // Load arguments descriptor into EDX. |
| 1303 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); | 1379 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); |
| 1304 // Loop that checks if there is an IC data match. | 1380 // Loop that checks if there is an IC data match. |
| 1305 Label loop, update, test, found; | 1381 Label loop, update, test, found; |
| 1306 // ECX: IC data object (preserved). | 1382 // ECX: IC data object (preserved). |
| 1307 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); | 1383 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); |
| 1308 // EBX: ic_data_array with check entries: classes and target functions. | 1384 // EBX: ic_data_array with check entries: classes and target functions. |
| 1309 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); | 1385 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); |
| 1310 // EBX: points directly to the first ic data array element. | 1386 // EBX: points directly to the first ic data array element. |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1421 // ECX: Inline cache data object. | 1497 // ECX: Inline cache data object. |
| 1422 // TOS(0): Return address. | 1498 // TOS(0): Return address. |
| 1423 // Inline cache data object structure: | 1499 // Inline cache data object structure: |
| 1424 // 0: function-name | 1500 // 0: function-name |
| 1425 // 1: N, number of arguments checked. | 1501 // 1: N, number of arguments checked. |
| 1426 // 2 .. (length - 1): group of checks, each check containing: | 1502 // 2 .. (length - 1): group of checks, each check containing: |
| 1427 // - N classes. | 1503 // - N classes. |
| 1428 // - 1 target function. | 1504 // - 1 target function. |
| 1429 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1505 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1430 GenerateUsageCounterIncrement(assembler, EBX); | 1506 GenerateUsageCounterIncrement(assembler, EBX); |
| 1431 GenerateNArgsCheckInlineCacheStub( | 1507 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1432 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1508 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1433 } | 1509 } |
| 1434 | 1510 |
| 1435 | 1511 |
| 1436 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1512 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1437 GenerateUsageCounterIncrement(assembler, EBX); | 1513 GenerateUsageCounterIncrement(assembler, EBX); |
| 1438 GenerateNArgsCheckInlineCacheStub( | 1514 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1439 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1515 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1440 } | 1516 } |
| 1441 | 1517 |
| 1442 | 1518 |
| 1443 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1519 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1444 GenerateUsageCounterIncrement(assembler, EBX); | 1520 GenerateUsageCounterIncrement(assembler, EBX); |
| 1445 GenerateNArgsCheckInlineCacheStub( | 1521 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1446 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1522 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1523 } | |
| 1524 | |
| 1525 | |
| 1526 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { | |
| 1527 GenerateUsageCounterIncrement(assembler, EBX); | |
| 1528 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1529 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); | |
| 1530 } | |
| 1531 | |
| 1532 | |
| 1533 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { | |
| 1534 GenerateUsageCounterIncrement(assembler, EBX); | |
| 1535 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1536 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); | |
| 1537 } | |
| 1538 | |
| 1539 | |
| 1540 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { | |
| 1541 GenerateUsageCounterIncrement(assembler, EBX); | |
| 1542 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1543 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); | |
| 1447 } | 1544 } |
| 1448 | 1545 |
| 1449 | 1546 |
| 1450 // Use inline cache data array to invoke the target or continue in inline | 1547 // Use inline cache data array to invoke the target or continue in inline |
| 1451 // cache miss handler. Stub for 1-argument check (receiver class). | 1548 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1452 // EDI: function which counter needs to be incremented. | 1549 // EDI: function which counter needs to be incremented. |
| 1453 // ECX: Inline cache data object. | 1550 // ECX: Inline cache data object. |
| 1454 // TOS(0): Return address. | 1551 // TOS(0): Return address. |
| 1455 // Inline cache data object structure: | 1552 // Inline cache data object structure: |
| 1456 // 0: function-name | 1553 // 0: function-name |
| 1457 // 1: N, number of arguments checked. | 1554 // 1: N, number of arguments checked. |
| 1458 // 2 .. (length - 1): group of checks, each check containing: | 1555 // 2 .. (length - 1): group of checks, each check containing: |
| 1459 // - N classes. | 1556 // - N classes. |
| 1460 // - 1 target function. | 1557 // - 1 target function. |
| 1461 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1558 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1462 Assembler* assembler) { | 1559 Assembler* assembler) { |
| 1463 GenerateOptimizedUsageCounterIncrement(assembler); | 1560 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1464 GenerateNArgsCheckInlineCacheStub( | 1561 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1465 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1562 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1466 } | 1563 } |
| 1467 | 1564 |
| 1468 | 1565 |
| 1469 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1566 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1470 Assembler* assembler) { | 1567 Assembler* assembler) { |
| 1471 GenerateOptimizedUsageCounterIncrement(assembler); | 1568 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1472 GenerateNArgsCheckInlineCacheStub( | 1569 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1473 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1570 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1474 } | 1571 } |
| 1475 | 1572 |
| 1476 | 1573 |
| 1477 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1574 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1478 Assembler* assembler) { | 1575 Assembler* assembler) { |
| 1479 GenerateOptimizedUsageCounterIncrement(assembler); | 1576 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1480 GenerateNArgsCheckInlineCacheStub( | 1577 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1481 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1578 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1482 } | 1579 } |
| 1483 | 1580 |
| 1484 | 1581 |
| 1485 // Do not count as no type feedback is collected. | 1582 // Do not count as no type feedback is collected. |
| 1486 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1583 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1487 GenerateNArgsCheckInlineCacheStub( | 1584 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1488 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1585 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1489 } | 1586 } |
| 1490 | 1587 |
| 1491 | 1588 |
| 1492 // Intermediary stub between a static call and its target. ICData contains | 1589 // Intermediary stub between a static call and its target. ICData contains |
| 1493 // the target function and the call count. | 1590 // the target function and the call count. |
| 1494 // ECX: ICData | 1591 // ECX: ICData |
| 1495 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1592 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1496 GenerateUsageCounterIncrement(assembler, EBX); | 1593 GenerateUsageCounterIncrement(assembler, EBX); |
| 1497 | 1594 |
| 1498 #if defined(DEBUG) | 1595 #if defined(DEBUG) |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1545 __ movl(EBX, FieldAddress(EAX, Function::instructions_offset())); | 1642 __ movl(EBX, FieldAddress(EAX, Function::instructions_offset())); |
| 1546 | 1643 |
| 1547 // EBX: Target instructions. | 1644 // EBX: Target instructions. |
| 1548 __ addl(EBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); | 1645 __ addl(EBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 1549 __ jmp(EBX); | 1646 __ jmp(EBX); |
| 1550 } | 1647 } |
| 1551 | 1648 |
| 1552 | 1649 |
| 1553 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1650 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1554 GenerateUsageCounterIncrement(assembler, EBX); | 1651 GenerateUsageCounterIncrement(assembler, EBX); |
| 1555 GenerateNArgsCheckInlineCacheStub( | 1652 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1556 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); | 1653 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1557 } | 1654 } |
| 1558 | 1655 |
| 1559 | 1656 |
| 1560 // Stub for compiling a function and jumping to the compiled code. | 1657 // Stub for compiling a function and jumping to the compiled code. |
| 1561 // ECX: IC-Data (for methods). | 1658 // ECX: IC-Data (for methods). |
| 1562 // EDX: Arguments descriptor. | 1659 // EDX: Arguments descriptor. |
| 1563 // EAX: Function. | 1660 // EAX: Function. |
| 1564 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1661 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1565 __ EnterStubFrame(); | 1662 __ EnterStubFrame(); |
| 1566 __ pushl(EDX); // Preserve arguments descriptor array. | 1663 __ pushl(EDX); // Preserve arguments descriptor array. |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1929 const Register temp = ECX; | 2026 const Register temp = ECX; |
| 1930 __ movl(left, Address(ESP, 2 * kWordSize)); | 2027 __ movl(left, Address(ESP, 2 * kWordSize)); |
| 1931 __ movl(right, Address(ESP, 1 * kWordSize)); | 2028 __ movl(right, Address(ESP, 1 * kWordSize)); |
| 1932 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2029 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1933 __ ret(); | 2030 __ ret(); |
| 1934 } | 2031 } |
| 1935 | 2032 |
| 1936 } // namespace dart | 2033 } // namespace dart |
| 1937 | 2034 |
| 1938 #endif // defined TARGET_ARCH_IA32 | 2035 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |