| 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_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 1354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 Register ic_reg = S5; | 1365 Register ic_reg = S5; |
| 1366 Register func_reg = temp_reg; | 1366 Register func_reg = temp_reg; |
| 1367 ASSERT(temp_reg == T0); | 1367 ASSERT(temp_reg == T0); |
| 1368 __ lw(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); | 1368 __ lw(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); |
| 1369 __ lw(T1, FieldAddress(func_reg, Function::usage_counter_offset())); | 1369 __ lw(T1, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1370 __ addiu(T1, T1, Immediate(1)); | 1370 __ addiu(T1, T1, Immediate(1)); |
| 1371 __ sw(T1, FieldAddress(func_reg, Function::usage_counter_offset())); | 1371 __ sw(T1, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1372 } | 1372 } |
| 1373 | 1373 |
| 1374 | 1374 |
| 1375 // Note: S5 must be preserved. |
| 1376 // Attempt a quick Smi operation for known operations ('kind'). The ICData |
| 1377 // must have been primed with a Smi/Smi check that will be used for counting |
| 1378 // the invocations. |
| 1379 static void EmitFastSmiOp(Assembler* assembler, |
| 1380 Token::Kind kind, |
| 1381 intptr_t num_args, |
| 1382 Label* not_smi_or_overflow) { |
| 1383 ASSERT(num_args == 2); |
| 1384 __ lw(T0, Address(SP, 0 * kWordSize)); // Left. |
| 1385 __ lw(T1, Address(SP, 1 * kWordSize)); // Right. |
| 1386 __ or_(CMPRES1, T0, T1); |
| 1387 __ andi(CMPRES1, CMPRES1, Immediate(kSmiTagMask)); |
| 1388 __ bne(CMPRES1, ZR, not_smi_or_overflow); |
| 1389 switch (kind) { |
| 1390 case Token::kADD: { |
| 1391 __ AdduDetectOverflow(V0, T1, T0, CMPRES1); // Add. |
| 1392 __ bltz(CMPRES1, not_smi_or_overflow); // Fall through on overflow. |
| 1393 break; |
| 1394 } |
| 1395 case Token::kSUB: { |
| 1396 __ SubuDetectOverflow(V0, T1, T0, CMPRES1); // Subtract. |
| 1397 __ bltz(CMPRES1, not_smi_or_overflow); // Fall through on overflow. |
| 1398 break; |
| 1399 } |
| 1400 case Token::kEQ: { |
| 1401 Label true_label, done; |
| 1402 __ beq(T1, T0, &true_label); |
| 1403 __ LoadObject(V0, Bool::False()); |
| 1404 __ b(&done); |
| 1405 __ Bind(&true_label); |
| 1406 __ LoadObject(V0, Bool::True()); |
| 1407 __ Bind(&done); |
| 1408 break; |
| 1409 } |
| 1410 default: UNIMPLEMENTED(); |
| 1411 } |
| 1412 // S5: IC data object (preserved). |
| 1413 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); |
| 1414 // T0: ic_data_array with check entries: classes and target functions. |
| 1415 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); |
| 1416 // T0: points directly to the first ic data array element. |
| 1417 #if defined(DEBUG) |
| 1418 // Check that first entry is for Smi/Smi. |
| 1419 Label error, ok; |
| 1420 const int32_t imm_smi_cid = reinterpret_cast<int32_t>(Smi::New(kSmiCid)); |
| 1421 __ lw(T4, Address(T0)); |
| 1422 __ BranchNotEqual(T4, imm_smi_cid, &error); |
| 1423 __ lw(T4, Address(T0, kWordSize)); |
| 1424 __ BranchEqual(T4, imm_smi_cid, &ok); |
| 1425 __ Bind(&error); |
| 1426 __ Stop("Incorrect IC data"); |
| 1427 __ Bind(&ok); |
| 1428 #endif |
| 1429 // Update counter. |
| 1430 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1431 __ lw(T4, Address(T0, count_offset)); |
| 1432 __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6); |
| 1433 __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow. |
| 1434 __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue)); |
| 1435 __ movz(T4, T7, CMPRES1); |
| 1436 __ sw(T4, Address(T0, count_offset)); |
| 1437 |
| 1438 __ Ret(); |
| 1439 } |
| 1440 |
| 1441 |
| 1375 // Generate inline cache check for 'num_args'. | 1442 // Generate inline cache check for 'num_args'. |
| 1376 // RA: return address | 1443 // RA: return address |
| 1377 // S5: Inline cache data object. | 1444 // S5: Inline cache data object. |
| 1378 // Control flow: | 1445 // Control flow: |
| 1379 // - If receiver is null -> jump to IC miss. | 1446 // - If receiver is null -> jump to IC miss. |
| 1380 // - If receiver is Smi -> load Smi class. | 1447 // - If receiver is Smi -> load Smi class. |
| 1381 // - If receiver is not-Smi -> load receiver's class. | 1448 // - If receiver is not-Smi -> load receiver's class. |
| 1382 // - Check if 'num_args' (including receiver) match any IC data group. | 1449 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1383 // - Match found -> jump to target. | 1450 // - Match found -> jump to target. |
| 1384 // - Match not found -> jump to IC miss. | 1451 // - Match not found -> jump to IC miss. |
| 1385 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1452 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1386 Assembler* assembler, | 1453 Assembler* assembler, |
| 1387 intptr_t num_args, | 1454 intptr_t num_args, |
| 1388 const RuntimeEntry& handle_ic_miss) { | 1455 const RuntimeEntry& handle_ic_miss, |
| 1456 Token::Kind kind) { |
| 1389 __ TraceSimMsg("NArgsCheckInlineCacheStub"); | 1457 __ TraceSimMsg("NArgsCheckInlineCacheStub"); |
| 1390 ASSERT(num_args > 0); | 1458 ASSERT(num_args > 0); |
| 1391 #if defined(DEBUG) | 1459 #if defined(DEBUG) |
| 1392 { Label ok; | 1460 { Label ok; |
| 1393 // Check that the IC data array has NumArgsTested() == num_args. | 1461 // Check that the IC data array has NumArgsTested() == num_args. |
| 1394 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1462 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1395 __ lw(T0, FieldAddress(S5, ICData::state_bits_offset())); | 1463 __ lw(T0, FieldAddress(S5, ICData::state_bits_offset())); |
| 1396 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1464 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1397 __ andi(T0, T0, Immediate(ICData::NumArgsTestedMask())); | 1465 __ andi(T0, T0, Immediate(ICData::NumArgsTestedMask())); |
| 1398 __ BranchEqual(T0, num_args, &ok); | 1466 __ BranchEqual(T0, num_args, &ok); |
| 1399 __ Stop("Incorrect stub for IC data"); | 1467 __ Stop("Incorrect stub for IC data"); |
| 1400 __ Bind(&ok); | 1468 __ Bind(&ok); |
| 1401 } | 1469 } |
| 1402 #endif // DEBUG | 1470 #endif // DEBUG |
| 1403 | 1471 |
| 1404 | 1472 |
| 1405 Label stepping, done_stepping; | 1473 Label stepping, done_stepping; |
| 1406 // Check single stepping. | 1474 // Check single stepping. |
| 1407 __ lw(T0, FieldAddress(CTX, Context::isolate_offset())); | 1475 __ lw(T0, FieldAddress(CTX, Context::isolate_offset())); |
| 1408 __ lbu(T0, Address(T0, Isolate::single_step_offset())); | 1476 __ lbu(T0, Address(T0, Isolate::single_step_offset())); |
| 1409 __ BranchNotEqual(T0, 0, &stepping); | 1477 __ BranchNotEqual(T0, 0, &stepping); |
| 1410 __ Bind(&done_stepping); | 1478 __ Bind(&done_stepping); |
| 1411 | 1479 |
| 1480 if (kind != Token::kILLEGAL) { |
| 1481 Label not_smi_or_overflow; |
| 1482 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1483 __ Bind(¬_smi_or_overflow); |
| 1484 } |
| 1485 |
| 1412 // Load argument descriptor into S4. | 1486 // Load argument descriptor into S4. |
| 1413 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); | 1487 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); |
| 1414 // Preserve return address, since RA is needed for subroutine call. | 1488 // Preserve return address, since RA is needed for subroutine call. |
| 1415 __ mov(T2, RA); | 1489 __ mov(T2, RA); |
| 1416 // Loop that checks if there is an IC data match. | 1490 // Loop that checks if there is an IC data match. |
| 1417 Label loop, update, test, found; | 1491 Label loop, update, test, found; |
| 1418 // S5: IC data object (preserved). | 1492 // S5: IC data object (preserved). |
| 1419 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); | 1493 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); |
| 1420 // T0: ic_data_array with check entries: classes and target functions. | 1494 // T0: ic_data_array with check entries: classes and target functions. |
| 1421 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); | 1495 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1562 // RA: Return address. | 1636 // RA: Return address. |
| 1563 // S5: Inline cache data object. | 1637 // S5: Inline cache data object. |
| 1564 // Inline cache data object structure: | 1638 // Inline cache data object structure: |
| 1565 // 0: function-name | 1639 // 0: function-name |
| 1566 // 1: N, number of arguments checked. | 1640 // 1: N, number of arguments checked. |
| 1567 // 2 .. (length - 1): group of checks, each check containing: | 1641 // 2 .. (length - 1): group of checks, each check containing: |
| 1568 // - N classes. | 1642 // - N classes. |
| 1569 // - 1 target function. | 1643 // - 1 target function. |
| 1570 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1644 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1571 GenerateUsageCounterIncrement(assembler, T0); | 1645 GenerateUsageCounterIncrement(assembler, T0); |
| 1572 GenerateNArgsCheckInlineCacheStub( | 1646 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1573 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1647 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1574 } | 1648 } |
| 1575 | 1649 |
| 1576 | 1650 |
| 1577 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1651 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1578 GenerateUsageCounterIncrement(assembler, T0); | 1652 GenerateUsageCounterIncrement(assembler, T0); |
| 1579 GenerateNArgsCheckInlineCacheStub( | 1653 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1580 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1654 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1581 } | 1655 } |
| 1582 | 1656 |
| 1583 | 1657 |
| 1584 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1658 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1585 GenerateUsageCounterIncrement(assembler, T0); | 1659 GenerateUsageCounterIncrement(assembler, T0); |
| 1586 GenerateNArgsCheckInlineCacheStub( | 1660 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1587 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1661 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1662 } |
| 1663 |
| 1664 |
| 1665 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { |
| 1666 GenerateUsageCounterIncrement(assembler, T0); |
| 1667 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1668 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); |
| 1669 } |
| 1670 |
| 1671 |
| 1672 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { |
| 1673 GenerateUsageCounterIncrement(assembler, T0); |
| 1674 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1675 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); |
| 1676 } |
| 1677 |
| 1678 |
| 1679 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { |
| 1680 GenerateUsageCounterIncrement(assembler, T0); |
| 1681 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1682 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); |
| 1588 } | 1683 } |
| 1589 | 1684 |
| 1590 | 1685 |
| 1591 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1686 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1592 Assembler* assembler) { | 1687 Assembler* assembler) { |
| 1593 GenerateOptimizedUsageCounterIncrement(assembler); | 1688 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1594 GenerateNArgsCheckInlineCacheStub( | 1689 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1595 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1690 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1596 } | 1691 } |
| 1597 | 1692 |
| 1598 | 1693 |
| 1599 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1694 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1600 Assembler* assembler) { | 1695 Assembler* assembler) { |
| 1601 GenerateOptimizedUsageCounterIncrement(assembler); | 1696 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1602 GenerateNArgsCheckInlineCacheStub( | 1697 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1603 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1698 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1604 } | 1699 } |
| 1605 | 1700 |
| 1606 | 1701 |
| 1607 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1702 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1608 Assembler* assembler) { | 1703 Assembler* assembler) { |
| 1609 GenerateOptimizedUsageCounterIncrement(assembler); | 1704 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1610 GenerateNArgsCheckInlineCacheStub( | 1705 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1611 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1706 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1612 } | 1707 } |
| 1613 | 1708 |
| 1614 | 1709 |
| 1615 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1710 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1616 GenerateNArgsCheckInlineCacheStub( | 1711 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1617 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1712 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1618 } | 1713 } |
| 1619 | 1714 |
| 1620 | 1715 |
| 1621 // Intermediary stub between a static call and its target. ICData contains | 1716 // Intermediary stub between a static call and its target. ICData contains |
| 1622 // the target function and the call count. | 1717 // the target function and the call count. |
| 1623 // S5: ICData | 1718 // S5: ICData |
| 1624 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1719 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1625 GenerateUsageCounterIncrement(assembler, T0); | 1720 GenerateUsageCounterIncrement(assembler, T0); |
| 1626 __ TraceSimMsg("UnoptimizedStaticCallStub"); | 1721 __ TraceSimMsg("UnoptimizedStaticCallStub"); |
| 1627 #if defined(DEBUG) | 1722 #if defined(DEBUG) |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1682 __ lw(S5, Address(SP, 1 * kWordSize)); | 1777 __ lw(S5, Address(SP, 1 * kWordSize)); |
| 1683 __ addiu(SP, SP, Immediate(2 * kWordSize)); | 1778 __ addiu(SP, SP, Immediate(2 * kWordSize)); |
| 1684 __ LeaveStubFrame(); | 1779 __ LeaveStubFrame(); |
| 1685 __ b(&done_stepping); | 1780 __ b(&done_stepping); |
| 1686 } | 1781 } |
| 1687 | 1782 |
| 1688 | 1783 |
| 1689 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1784 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1690 GenerateUsageCounterIncrement(assembler, T0); | 1785 GenerateUsageCounterIncrement(assembler, T0); |
| 1691 GenerateNArgsCheckInlineCacheStub( | 1786 GenerateNArgsCheckInlineCacheStub( |
| 1692 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry); | 1787 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1693 } | 1788 } |
| 1694 | 1789 |
| 1695 | 1790 |
| 1696 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1791 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1697 GenerateUsageCounterIncrement(assembler, T0); | 1792 GenerateUsageCounterIncrement(assembler, T0); |
| 1698 GenerateNArgsCheckInlineCacheStub( | 1793 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1699 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); | 1794 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1700 } | 1795 } |
| 1701 | 1796 |
| 1702 | 1797 |
| 1703 // Stub for compiling a function and jumping to the compiled code. | 1798 // Stub for compiling a function and jumping to the compiled code. |
| 1704 // S5: IC-Data (for methods). | 1799 // S5: IC-Data (for methods). |
| 1705 // S4: Arguments descriptor. | 1800 // S4: Arguments descriptor. |
| 1706 // T0: Function. | 1801 // T0: Function. |
| 1707 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1802 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1708 __ EnterStubFrame(); | 1803 __ EnterStubFrame(); |
| 1709 __ addiu(SP, SP, Immediate(-3 * kWordSize)); | 1804 __ addiu(SP, SP, Immediate(-3 * kWordSize)); |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2113 const Register right = T0; | 2208 const Register right = T0; |
| 2114 __ lw(left, Address(SP, 1 * kWordSize)); | 2209 __ lw(left, Address(SP, 1 * kWordSize)); |
| 2115 __ lw(right, Address(SP, 0 * kWordSize)); | 2210 __ lw(right, Address(SP, 0 * kWordSize)); |
| 2116 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp1, temp2); | 2211 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp1, temp2); |
| 2117 __ Ret(); | 2212 __ Ret(); |
| 2118 } | 2213 } |
| 2119 | 2214 |
| 2120 } // namespace dart | 2215 } // namespace dart |
| 2121 | 2216 |
| 2122 #endif // defined TARGET_ARCH_MIPS | 2217 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |