| 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_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 1306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1317 // - If receiver is Smi -> load Smi class. | 1317 // - If receiver is Smi -> load Smi class. |
| 1318 // - If receiver is not-Smi -> load receiver's class. | 1318 // - If receiver is not-Smi -> load receiver's class. |
| 1319 // - Check if 'num_args' (including receiver) match any IC data group. | 1319 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1320 // - Match found -> jump to target. | 1320 // - Match found -> jump to target. |
| 1321 // - Match not found -> jump to IC miss. | 1321 // - Match not found -> jump to IC miss. |
| 1322 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1322 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1323 Assembler* assembler, | 1323 Assembler* assembler, |
| 1324 intptr_t num_args, | 1324 intptr_t num_args, |
| 1325 const RuntimeEntry& handle_ic_miss, | 1325 const RuntimeEntry& handle_ic_miss, |
| 1326 Token::Kind kind, | 1326 Token::Kind kind, |
| 1327 RangeCollectionMode range_collection_mode, | |
| 1328 bool optimized) { | 1327 bool optimized) { |
| 1329 __ CheckCodePointer(); | 1328 __ CheckCodePointer(); |
| 1330 ASSERT(num_args > 0); | 1329 ASSERT(num_args > 0); |
| 1331 #if defined(DEBUG) | 1330 #if defined(DEBUG) |
| 1332 { Label ok; | 1331 { Label ok; |
| 1333 // Check that the IC data array has NumArgsTested() == num_args. | 1332 // Check that the IC data array has NumArgsTested() == num_args. |
| 1334 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1333 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1335 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); | 1334 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); |
| 1336 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1335 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1337 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); | 1336 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); |
| 1338 __ CompareImmediate(R8, num_args); | 1337 __ CompareImmediate(R8, num_args); |
| 1339 __ b(&ok, EQ); | 1338 __ b(&ok, EQ); |
| 1340 __ Stop("Incorrect stub for IC data"); | 1339 __ Stop("Incorrect stub for IC data"); |
| 1341 __ Bind(&ok); | 1340 __ Bind(&ok); |
| 1342 } | 1341 } |
| 1343 #endif // DEBUG | 1342 #endif // DEBUG |
| 1344 | 1343 |
| 1345 Label stepping, done_stepping; | 1344 Label stepping, done_stepping; |
| 1346 if (FLAG_support_debugger && !optimized) { | 1345 if (FLAG_support_debugger && !optimized) { |
| 1347 __ Comment("Check single stepping"); | 1346 __ Comment("Check single stepping"); |
| 1348 __ LoadIsolate(R8); | 1347 __ LoadIsolate(R8); |
| 1349 __ ldrb(R8, Address(R8, Isolate::single_step_offset())); | 1348 __ ldrb(R8, Address(R8, Isolate::single_step_offset())); |
| 1350 __ CompareImmediate(R8, 0); | 1349 __ CompareImmediate(R8, 0); |
| 1351 __ b(&stepping, NE); | 1350 __ b(&stepping, NE); |
| 1352 __ Bind(&done_stepping); | 1351 __ Bind(&done_stepping); |
| 1353 } | 1352 } |
| 1354 | 1353 |
| 1355 __ Comment("Range feedback collection"); | |
| 1356 Label not_smi_or_overflow; | 1354 Label not_smi_or_overflow; |
| 1357 if (range_collection_mode == kCollectRanges) { | |
| 1358 ASSERT((num_args == 1) || (num_args == 2)); | |
| 1359 if (num_args == 2) { | |
| 1360 __ ldr(R0, Address(SP, 1 * kWordSize)); | |
| 1361 __ UpdateRangeFeedback(R0, 0, R9, R1, R4, ¬_smi_or_overflow); | |
| 1362 } | |
| 1363 | |
| 1364 __ ldr(R0, Address(SP, 0 * kWordSize)); | |
| 1365 __ UpdateRangeFeedback(R0, num_args - 1, R9, R1, R4, ¬_smi_or_overflow); | |
| 1366 } | |
| 1367 if (kind != Token::kILLEGAL) { | 1355 if (kind != Token::kILLEGAL) { |
| 1368 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | 1356 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1369 } | 1357 } |
| 1370 __ Bind(¬_smi_or_overflow); | 1358 __ Bind(¬_smi_or_overflow); |
| 1371 | 1359 |
| 1372 __ Comment("Extract ICData initial values and receiver cid"); | 1360 __ Comment("Extract ICData initial values and receiver cid"); |
| 1373 // Load arguments descriptor into R4. | 1361 // Load arguments descriptor into R4. |
| 1374 __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset())); | 1362 __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset())); |
| 1375 // Loop that checks if there is an IC data match. | 1363 // Loop that checks if there is an IC data match. |
| 1376 Label loop, update, test, found; | 1364 Label loop, update, test, found; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1471 __ LoadFromOffset(kWord, R1, R8, count_offset); | 1459 __ LoadFromOffset(kWord, R1, R8, count_offset); |
| 1472 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1460 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1473 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. | 1461 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1474 __ StoreIntoSmiField(Address(R8, count_offset), R1); | 1462 __ StoreIntoSmiField(Address(R8, count_offset), R1); |
| 1475 } | 1463 } |
| 1476 | 1464 |
| 1477 __ Comment("Call target"); | 1465 __ Comment("Call target"); |
| 1478 __ Bind(&call_target_function); | 1466 __ Bind(&call_target_function); |
| 1479 // R0: target function. | 1467 // R0: target function. |
| 1480 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 1468 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| 1481 if (range_collection_mode == kCollectRanges) { | 1469 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1482 __ ldr(R1, Address(SP, 0 * kWordSize)); | 1470 __ bx(R2); |
| 1483 if (num_args == 2) { | |
| 1484 __ ldr(R3, Address(SP, 1 * kWordSize)); | |
| 1485 } | |
| 1486 __ EnterStubFrame(); | |
| 1487 if (num_args == 2) { | |
| 1488 __ PushList((1 << R1) | (1 << R3) | (1 << R9)); | |
| 1489 } else { | |
| 1490 __ PushList((1 << R1) | (1 << R9)); | |
| 1491 } | |
| 1492 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); | |
| 1493 __ blx(R2); | |
| 1494 | |
| 1495 Label done; | |
| 1496 __ ldr(R9, Address(FP, kFirstLocalSlotFromFp * kWordSize)); | |
| 1497 __ UpdateRangeFeedback(R0, 2, R9, R1, R4, &done); | |
| 1498 __ Bind(&done); | |
| 1499 __ RestoreCodePointer(); | |
| 1500 __ LeaveStubFrame(); | |
| 1501 __ Ret(); | |
| 1502 } else { | |
| 1503 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); | |
| 1504 __ bx(R2); | |
| 1505 } | |
| 1506 | 1471 |
| 1507 if (FLAG_support_debugger && !optimized) { | 1472 if (FLAG_support_debugger && !optimized) { |
| 1508 __ Bind(&stepping); | 1473 __ Bind(&stepping); |
| 1509 __ EnterStubFrame(); | 1474 __ EnterStubFrame(); |
| 1510 __ Push(R9); // Preserve IC data. | 1475 __ Push(R9); // Preserve IC data. |
| 1511 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1476 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1512 __ Pop(R9); | 1477 __ Pop(R9); |
| 1513 __ RestoreCodePointer(); | 1478 __ RestoreCodePointer(); |
| 1514 __ LeaveStubFrame(); | 1479 __ LeaveStubFrame(); |
| 1515 __ b(&done_stepping); | 1480 __ b(&done_stepping); |
| 1516 } | 1481 } |
| 1517 } | 1482 } |
| 1518 | 1483 |
| 1519 | 1484 |
| 1520 // Use inline cache data array to invoke the target or continue in inline | 1485 // Use inline cache data array to invoke the target or continue in inline |
| 1521 // cache miss handler. Stub for 1-argument check (receiver class). | 1486 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1522 // LR: return address. | 1487 // LR: return address. |
| 1523 // R9: inline cache data object. | 1488 // R9: inline cache data object. |
| 1524 // Inline cache data object structure: | 1489 // Inline cache data object structure: |
| 1525 // 0: function-name | 1490 // 0: function-name |
| 1526 // 1: N, number of arguments checked. | 1491 // 1: N, number of arguments checked. |
| 1527 // 2 .. (length - 1): group of checks, each check containing: | 1492 // 2 .. (length - 1): group of checks, each check containing: |
| 1528 // - N classes. | 1493 // - N classes. |
| 1529 // - 1 target function. | 1494 // - 1 target function. |
| 1530 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1495 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1531 GenerateUsageCounterIncrement(assembler, R8); | 1496 GenerateUsageCounterIncrement(assembler, R8); |
| 1532 GenerateNArgsCheckInlineCacheStub(assembler, | 1497 GenerateNArgsCheckInlineCacheStub(assembler, |
| 1533 1, | 1498 1, |
| 1534 kInlineCacheMissHandlerOneArgRuntimeEntry, | 1499 kInlineCacheMissHandlerOneArgRuntimeEntry, |
| 1535 Token::kILLEGAL, | 1500 Token::kILLEGAL); |
| 1536 kIgnoreRanges); | |
| 1537 } | 1501 } |
| 1538 | 1502 |
| 1539 | 1503 |
| 1540 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1504 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1541 GenerateUsageCounterIncrement(assembler, R8); | 1505 GenerateUsageCounterIncrement(assembler, R8); |
| 1542 GenerateNArgsCheckInlineCacheStub(assembler, | 1506 GenerateNArgsCheckInlineCacheStub(assembler, |
| 1543 2, | 1507 2, |
| 1544 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1508 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1545 Token::kILLEGAL, | 1509 Token::kILLEGAL); |
| 1546 kIgnoreRanges); | |
| 1547 } | 1510 } |
| 1548 | 1511 |
| 1549 | 1512 |
| 1550 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { | 1513 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { |
| 1551 GenerateUsageCounterIncrement(assembler, R8); | 1514 GenerateUsageCounterIncrement(assembler, R8); |
| 1552 GenerateNArgsCheckInlineCacheStub(assembler, | 1515 GenerateNArgsCheckInlineCacheStub(assembler, |
| 1553 2, | 1516 2, |
| 1554 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1517 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1555 Token::kADD, | 1518 Token::kADD); |
| 1556 kCollectRanges); | |
| 1557 } | 1519 } |
| 1558 | 1520 |
| 1559 | 1521 |
| 1560 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { | 1522 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { |
| 1561 GenerateUsageCounterIncrement(assembler, R8); | 1523 GenerateUsageCounterIncrement(assembler, R8); |
| 1562 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1524 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1563 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB, | 1525 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); |
| 1564 kCollectRanges); | |
| 1565 } | 1526 } |
| 1566 | 1527 |
| 1567 | 1528 |
| 1568 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { | 1529 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { |
| 1569 GenerateUsageCounterIncrement(assembler, R8); | 1530 GenerateUsageCounterIncrement(assembler, R8); |
| 1570 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1531 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1571 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ, | 1532 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); |
| 1572 kIgnoreRanges); | |
| 1573 } | 1533 } |
| 1574 | 1534 |
| 1575 | 1535 |
| 1576 void StubCode::GenerateUnaryRangeCollectingInlineCacheStub( | 1536 void StubCode::GenerateUnaryRangeCollectingInlineCacheStub( |
| 1577 Assembler* assembler) { | 1537 Assembler* assembler) { |
| 1578 GenerateUsageCounterIncrement(assembler, R8); | 1538 GenerateUsageCounterIncrement(assembler, R8); |
| 1579 GenerateNArgsCheckInlineCacheStub(assembler, 1, | 1539 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1580 kInlineCacheMissHandlerOneArgRuntimeEntry, | 1540 kInlineCacheMissHandlerOneArgRuntimeEntry, |
| 1581 Token::kILLEGAL, | 1541 Token::kILLEGAL); |
| 1582 kCollectRanges); | |
| 1583 } | 1542 } |
| 1584 | 1543 |
| 1585 | 1544 |
| 1586 void StubCode::GenerateBinaryRangeCollectingInlineCacheStub( | 1545 void StubCode::GenerateBinaryRangeCollectingInlineCacheStub( |
| 1587 Assembler* assembler) { | 1546 Assembler* assembler) { |
| 1588 GenerateUsageCounterIncrement(assembler, R8); | 1547 GenerateUsageCounterIncrement(assembler, R8); |
| 1589 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1548 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1590 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1549 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1591 Token::kILLEGAL, | 1550 Token::kILLEGAL); |
| 1592 kCollectRanges); | |
| 1593 } | 1551 } |
| 1594 | 1552 |
| 1595 | 1553 |
| 1596 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1554 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1597 Assembler* assembler) { | 1555 Assembler* assembler) { |
| 1598 GenerateOptimizedUsageCounterIncrement(assembler); | 1556 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1599 GenerateNArgsCheckInlineCacheStub(assembler, 1, | 1557 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1600 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, | 1558 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, |
| 1601 kIgnoreRanges, true /* optimized */); | 1559 true /* optimized */); |
| 1602 } | 1560 } |
| 1603 | 1561 |
| 1604 | 1562 |
| 1605 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1563 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1606 Assembler* assembler) { | 1564 Assembler* assembler) { |
| 1607 GenerateOptimizedUsageCounterIncrement(assembler); | 1565 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1608 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1566 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1609 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL, | 1567 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL, |
| 1610 kIgnoreRanges, true /* optimized */); | 1568 true /* optimized */); |
| 1611 } | 1569 } |
| 1612 | 1570 |
| 1613 | 1571 |
| 1614 // Intermediary stub between a static call and its target. ICData contains | 1572 // Intermediary stub between a static call and its target. ICData contains |
| 1615 // the target function and the call count. | 1573 // the target function and the call count. |
| 1616 // R9: ICData | 1574 // R9: ICData |
| 1617 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1575 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1618 GenerateUsageCounterIncrement(assembler, R8); | 1576 GenerateUsageCounterIncrement(assembler, R8); |
| 1619 #if defined(DEBUG) | 1577 #if defined(DEBUG) |
| 1620 { Label ok; | 1578 { Label ok; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1674 __ RestoreCodePointer(); | 1632 __ RestoreCodePointer(); |
| 1675 __ LeaveStubFrame(); | 1633 __ LeaveStubFrame(); |
| 1676 __ b(&done_stepping); | 1634 __ b(&done_stepping); |
| 1677 } | 1635 } |
| 1678 } | 1636 } |
| 1679 | 1637 |
| 1680 | 1638 |
| 1681 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1639 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1682 GenerateUsageCounterIncrement(assembler, R8); | 1640 GenerateUsageCounterIncrement(assembler, R8); |
| 1683 GenerateNArgsCheckInlineCacheStub( | 1641 GenerateNArgsCheckInlineCacheStub( |
| 1684 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL, | 1642 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1685 kIgnoreRanges); | |
| 1686 } | 1643 } |
| 1687 | 1644 |
| 1688 | 1645 |
| 1689 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1646 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1690 GenerateUsageCounterIncrement(assembler, R8); | 1647 GenerateUsageCounterIncrement(assembler, R8); |
| 1691 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1648 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1692 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL, | 1649 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1693 kIgnoreRanges); | |
| 1694 } | 1650 } |
| 1695 | 1651 |
| 1696 | 1652 |
| 1697 // Stub for compiling a function and jumping to the compiled code. | 1653 // Stub for compiling a function and jumping to the compiled code. |
| 1698 // R9: IC-Data (for methods). | 1654 // R9: IC-Data (for methods). |
| 1699 // R4: Arguments descriptor. | 1655 // R4: Arguments descriptor. |
| 1700 // R0: Function. | 1656 // R0: Function. |
| 1701 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1657 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1702 // Preserve arg desc. and IC data object. | 1658 // Preserve arg desc. and IC data object. |
| 1703 __ EnterStubFrame(); | 1659 __ EnterStubFrame(); |
| (...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2181 } | 2137 } |
| 2182 | 2138 |
| 2183 | 2139 |
| 2184 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2140 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
| 2185 __ bkpt(0); | 2141 __ bkpt(0); |
| 2186 } | 2142 } |
| 2187 | 2143 |
| 2188 } // namespace dart | 2144 } // namespace dart |
| 2189 | 2145 |
| 2190 #endif // defined TARGET_ARCH_ARM | 2146 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |