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 1385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1396 const int32_t imm_smi_cid = reinterpret_cast<int32_t>(Smi::New(kSmiCid)); | 1396 const int32_t imm_smi_cid = reinterpret_cast<int32_t>(Smi::New(kSmiCid)); |
1397 __ lw(T4, Address(T0)); | 1397 __ lw(T4, Address(T0)); |
1398 __ BranchNotEqual(T4, Immediate(imm_smi_cid), &error); | 1398 __ BranchNotEqual(T4, Immediate(imm_smi_cid), &error); |
1399 __ lw(T4, Address(T0, kWordSize)); | 1399 __ lw(T4, Address(T0, kWordSize)); |
1400 __ BranchEqual(T4, Immediate(imm_smi_cid), &ok); | 1400 __ BranchEqual(T4, Immediate(imm_smi_cid), &ok); |
1401 __ Bind(&error); | 1401 __ Bind(&error); |
1402 __ Stop("Incorrect IC data"); | 1402 __ Stop("Incorrect IC data"); |
1403 __ Bind(&ok); | 1403 __ Bind(&ok); |
1404 #endif | 1404 #endif |
1405 if (FLAG_optimization_counter_threshold >= 0) { | 1405 if (FLAG_optimization_counter_threshold >= 0) { |
1406 // Update counter, ignore overflow. | 1406 // Update counter. |
1407 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1407 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
1408 __ lw(T4, Address(T0, count_offset)); | 1408 __ lw(T4, Address(T0, count_offset)); |
1409 __ AddImmediate(T4, T4, Smi::RawValue(1)); | 1409 __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6); |
| 1410 __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow. |
| 1411 __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue)); |
| 1412 __ movz(T4, T7, CMPRES1); |
1410 __ sw(T4, Address(T0, count_offset)); | 1413 __ sw(T4, Address(T0, count_offset)); |
1411 } | 1414 } |
1412 | 1415 |
1413 __ Ret(); | 1416 __ Ret(); |
1414 } | 1417 } |
1415 | 1418 |
1416 | 1419 |
1417 // Generate inline cache check for 'num_args'. | 1420 // Generate inline cache check for 'num_args'. |
1418 // RA: return address | 1421 // RA: return address |
1419 // S5: Inline cache data object. | 1422 // S5: Inline cache data object. |
1420 // Control flow: | 1423 // Control flow: |
1421 // - If receiver is null -> jump to IC miss. | 1424 // - If receiver is null -> jump to IC miss. |
1422 // - If receiver is Smi -> load Smi class. | 1425 // - If receiver is Smi -> load Smi class. |
1423 // - If receiver is not-Smi -> load receiver's class. | 1426 // - If receiver is not-Smi -> load receiver's class. |
1424 // - Check if 'num_args' (including receiver) match any IC data group. | 1427 // - Check if 'num_args' (including receiver) match any IC data group. |
1425 // - Match found -> jump to target. | 1428 // - Match found -> jump to target. |
1426 // - Match not found -> jump to IC miss. | 1429 // - Match not found -> jump to IC miss. |
1427 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1430 void StubCode::GenerateNArgsCheckInlineCacheStub( |
1428 Assembler* assembler, | 1431 Assembler* assembler, |
1429 intptr_t num_args, | 1432 intptr_t num_args, |
1430 const RuntimeEntry& handle_ic_miss, | 1433 const RuntimeEntry& handle_ic_miss, |
1431 Token::Kind kind, | 1434 Token::Kind kind, |
1432 bool optimized) { | 1435 bool optimized) { |
1433 __ Comment("NArgsCheckInlineCacheStub"); | 1436 __ Comment("NArgsCheckInlineCacheStub"); |
1434 ASSERT(num_args == 1 || num_args == 2); | 1437 ASSERT(num_args > 0); |
1435 #if defined(DEBUG) | 1438 #if defined(DEBUG) |
1436 { | 1439 { |
1437 Label ok; | 1440 Label ok; |
1438 // Check that the IC data array has NumArgsTested() == num_args. | 1441 // Check that the IC data array has NumArgsTested() == num_args. |
1439 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1442 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
1440 __ lw(T0, FieldAddress(S5, ICData::state_bits_offset())); | 1443 __ lw(T0, FieldAddress(S5, ICData::state_bits_offset())); |
1441 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1444 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
1442 __ andi(T0, T0, Immediate(ICData::NumArgsTestedMask())); | 1445 __ andi(T0, T0, Immediate(ICData::NumArgsTestedMask())); |
1443 __ BranchEqual(T0, Immediate(num_args), &ok); | 1446 __ BranchEqual(T0, Immediate(num_args), &ok); |
1444 __ Stop("Incorrect stub for IC data"); | 1447 __ Stop("Incorrect stub for IC data"); |
(...skipping 16 matching lines...) Expand all Loading... |
1461 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | 1464 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
1462 } | 1465 } |
1463 __ Bind(¬_smi_or_overflow); | 1466 __ Bind(¬_smi_or_overflow); |
1464 | 1467 |
1465 __ Comment("Extract ICData initial values and receiver cid"); | 1468 __ Comment("Extract ICData initial values and receiver cid"); |
1466 // Load argument descriptor into S4. | 1469 // Load argument descriptor into S4. |
1467 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); | 1470 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); |
1468 // Preserve return address, since RA is needed for subroutine call. | 1471 // Preserve return address, since RA is needed for subroutine call. |
1469 __ mov(T2, RA); | 1472 __ mov(T2, RA); |
1470 // Loop that checks if there is an IC data match. | 1473 // Loop that checks if there is an IC data match. |
1471 Label loop, found, miss; | 1474 Label loop, update, test, found; |
1472 // S5: IC data object (preserved). | 1475 // S5: IC data object (preserved). |
1473 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); | 1476 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); |
1474 // T0: ic_data_array with check entries: classes and target functions. | 1477 // T0: ic_data_array with check entries: classes and target functions. |
1475 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); | 1478 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); |
1476 // T0: points directly to the first ic data array element. | 1479 // T0: points directly to the first ic data array element. |
1477 | 1480 |
1478 // Get the receiver's class ID (first read number of arguments from | 1481 // Get the receiver's class ID (first read number of arguments from |
1479 // arguments descriptor array and then access the receiver from the stack). | 1482 // arguments descriptor array and then access the receiver from the stack). |
1480 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); | 1483 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); |
1481 __ LoadImmediate(TMP, Smi::RawValue(1)); | 1484 __ LoadImmediate(TMP, Smi::RawValue(1)); |
1482 __ subu(T1, T1, TMP); | 1485 __ subu(T1, T1, TMP); |
1483 __ sll(T3, T1, 1); // T1 (argument_count - 1) is smi. | 1486 __ sll(T3, T1, 1); // T1 (argument_count - 1) is smi. |
1484 __ addu(T3, T3, SP); | 1487 __ addu(T3, T3, SP); |
1485 __ lw(T3, Address(T3)); | 1488 __ lw(T3, Address(T3)); |
1486 __ LoadTaggedClassIdMayBeSmi(T3, T3); | 1489 __ LoadTaggedClassIdMayBeSmi(T3, T3); |
1487 | 1490 |
1488 if (num_args == 2) { | |
1489 __ LoadImmediate(TMP, Smi::RawValue(1)); | |
1490 __ subu(T5, T1, TMP); | |
1491 __ sll(T5, T5, 1); | |
1492 __ addu(T5, SP, T5); | |
1493 __ lw(T5, Address(T5)); | |
1494 __ LoadTaggedClassIdMayBeSmi(T5, T5); | |
1495 } | |
1496 | |
1497 // T1: argument_count - 1 (smi). | 1491 // T1: argument_count - 1 (smi). |
1498 // T3: receiver's class ID (smi). | 1492 // T3: receiver's class ID (smi). |
1499 // T5: first argument's class ID (smi). | 1493 __ b(&test); |
1500 | 1494 __ delay_slot()->lw(T4, Address(T0)); // First class id (smi) to check. |
1501 // We unroll the generic one that is generated once more than the others. | |
1502 bool optimize = kind == Token::kILLEGAL; | |
1503 | 1495 |
1504 __ Comment("ICData loop"); | 1496 __ Comment("ICData loop"); |
1505 __ Bind(&loop); | 1497 __ Bind(&loop); |
1506 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) { | 1498 for (int i = 0; i < num_args; i++) { |
1507 Label update; | 1499 if (i > 0) { |
1508 for (int i = 0; i < num_args; i++) { | 1500 // If not the first, load the next argument's class ID. |
| 1501 __ LoadImmediate(T3, Smi::RawValue(-i)); |
| 1502 __ addu(T3, T1, T3); |
| 1503 __ sll(T3, T3, 1); |
| 1504 __ addu(T3, SP, T3); |
| 1505 __ lw(T3, Address(T3)); |
| 1506 __ LoadTaggedClassIdMayBeSmi(T3, T3); |
| 1507 // T3: next argument class ID (smi). |
1509 __ lw(T4, Address(T0, i * kWordSize)); | 1508 __ lw(T4, Address(T0, i * kWordSize)); |
1510 if (i == 0) { | 1509 // T4: next class ID to check (smi). |
1511 if (num_args == 1) { | |
1512 __ beq(T3, T4, &found); // IC hit. | |
1513 } else { | |
1514 __ bne(T3, T4, &update); // Continue. | |
1515 } | |
1516 } else { | |
1517 __ beq(T5, T4, &found); // IC hit. | |
1518 } | |
1519 } | 1510 } |
1520 __ Bind(&update); | 1511 if (i < (num_args - 1)) { |
1521 | 1512 __ bne(T3, T4, &update); // Continue. |
1522 const intptr_t entry_size = | |
1523 ICData::TestEntryLengthFor(num_args) * kWordSize; | |
1524 __ AddImmediate(T0, entry_size); // Next entry. | |
1525 if (unroll == 0) { | |
1526 __ BranchNotEqual(T4, Immediate(Smi::RawValue(kIllegalCid)), | |
1527 &loop); // Done? | |
1528 } else { | 1513 } else { |
1529 __ BranchEqual(T4, Immediate(Smi::RawValue(kIllegalCid)), | 1514 // Last check, all checks before matched. |
1530 &miss); // Done? | 1515 Label skip; |
| 1516 __ bne(T3, T4, &skip); |
| 1517 __ b(&found); // Break. |
| 1518 __ delay_slot()->mov(RA, T2); // Restore return address if found. |
| 1519 __ Bind(&skip); |
1531 } | 1520 } |
1532 __ delay_slot()->lw(T4, Address(T0)); // Next class ID. | 1521 } |
| 1522 __ Bind(&update); |
| 1523 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 1524 if (num_args > 1) { |
| 1525 __ sll(T3, T1, 1); |
| 1526 __ addu(T3, T3, SP); |
| 1527 __ lw(T3, Address(T3)); |
| 1528 __ LoadTaggedClassIdMayBeSmi(T3, T3); |
1533 } | 1529 } |
1534 | 1530 |
1535 __ Bind(&miss); | 1531 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 1532 __ AddImmediate(T0, entry_size); // Next entry. |
| 1533 __ lw(T4, Address(T0)); // Next class ID. |
| 1534 |
| 1535 __ Bind(&test); |
| 1536 __ BranchNotEqual(T4, Immediate(Smi::RawValue(kIllegalCid)), &loop); // Done? |
| 1537 |
1536 __ Comment("IC miss"); | 1538 __ Comment("IC miss"); |
1537 // Restore return address. | 1539 // Restore return address. |
1538 __ mov(RA, T2); | 1540 __ mov(RA, T2); |
1539 | 1541 |
1540 // Compute address of arguments (first read number of arguments from | 1542 // Compute address of arguments (first read number of arguments from |
1541 // arguments descriptor array and then compute address on the stack). | 1543 // arguments descriptor array and then compute address on the stack). |
1542 // T1: argument_count - 1 (smi). | 1544 // T1: argument_count - 1 (smi). |
1543 __ sll(T1, T1, 1); // T1 is Smi. | 1545 __ sll(T1, T1, 1); // T1 is Smi. |
1544 __ addu(T1, SP, T1); | 1546 __ addu(T1, SP, T1); |
1545 // T1: address of receiver. | 1547 // T1: address of receiver. |
(...skipping 29 matching lines...) Expand all Loading... |
1575 | 1577 |
1576 Label call_target_function; | 1578 Label call_target_function; |
1577 if (!FLAG_lazy_dispatchers) { | 1579 if (!FLAG_lazy_dispatchers) { |
1578 __ mov(T0, T3); | 1580 __ mov(T0, T3); |
1579 GenerateDispatcherCode(assembler, &call_target_function); | 1581 GenerateDispatcherCode(assembler, &call_target_function); |
1580 } else { | 1582 } else { |
1581 __ b(&call_target_function); | 1583 __ b(&call_target_function); |
1582 } | 1584 } |
1583 | 1585 |
1584 __ Bind(&found); | 1586 __ Bind(&found); |
1585 __ mov(RA, T2); // Restore return address if found. | |
1586 __ Comment("Update caller's counter"); | 1587 __ Comment("Update caller's counter"); |
1587 // T0: Pointer to an IC data check group. | 1588 // T0: Pointer to an IC data check group. |
1588 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1589 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
1589 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1590 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
1590 __ lw(T3, Address(T0, target_offset)); | 1591 __ lw(T3, Address(T0, target_offset)); |
1591 | 1592 |
1592 if (FLAG_optimization_counter_threshold >= 0) { | 1593 if (FLAG_optimization_counter_threshold >= 0) { |
1593 // Update counter, ignore overflow. | 1594 // Update counter. |
1594 __ lw(T4, Address(T0, count_offset)); | 1595 __ lw(T4, Address(T0, count_offset)); |
1595 __ AddImmediate(T4, T4, Smi::RawValue(1)); | 1596 __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6); |
| 1597 __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow. |
| 1598 __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue)); |
| 1599 __ movz(T4, T7, CMPRES1); |
1596 __ sw(T4, Address(T0, count_offset)); | 1600 __ sw(T4, Address(T0, count_offset)); |
1597 } | 1601 } |
1598 | 1602 |
1599 __ Comment("Call target"); | 1603 __ Comment("Call target"); |
1600 __ Bind(&call_target_function); | 1604 __ Bind(&call_target_function); |
1601 // T0 <- T3: Target function. | 1605 // T0 <- T3: Target function. |
1602 __ mov(T0, T3); | 1606 __ mov(T0, T3); |
1603 Label is_compiled; | 1607 Label is_compiled; |
1604 __ lw(T4, FieldAddress(T0, Function::entry_point_offset())); | 1608 __ lw(T4, FieldAddress(T0, Function::entry_point_offset())); |
1605 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | 1609 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1718 | 1722 |
1719 // S5: IC data object (preserved). | 1723 // S5: IC data object (preserved). |
1720 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); | 1724 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset())); |
1721 // T0: ic_data_array with entries: target functions and count. | 1725 // T0: ic_data_array with entries: target functions and count. |
1722 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); | 1726 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag); |
1723 // T0: points directly to the first ic data array element. | 1727 // T0: points directly to the first ic data array element. |
1724 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; | 1728 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; |
1725 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; | 1729 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; |
1726 | 1730 |
1727 if (FLAG_optimization_counter_threshold >= 0) { | 1731 if (FLAG_optimization_counter_threshold >= 0) { |
1728 // Increment count for this call, ignore overflow. | 1732 // Increment count for this call. |
1729 __ lw(T4, Address(T0, count_offset)); | 1733 __ lw(T4, Address(T0, count_offset)); |
1730 __ AddImmediate(T4, T4, Smi::RawValue(1)); | 1734 __ AddImmediateDetectOverflow(T7, T4, Smi::RawValue(1), T5, T6); |
| 1735 __ slt(CMPRES1, T5, ZR); // T5 is < 0 if there was overflow. |
| 1736 __ LoadImmediate(T4, Smi::RawValue(Smi::kMaxValue)); |
| 1737 __ movz(T4, T7, CMPRES1); |
1731 __ sw(T4, Address(T0, count_offset)); | 1738 __ sw(T4, Address(T0, count_offset)); |
1732 } | 1739 } |
1733 | 1740 |
1734 // Load arguments descriptor into S4. | 1741 // Load arguments descriptor into S4. |
1735 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); | 1742 __ lw(S4, FieldAddress(S5, ICData::arguments_descriptor_offset())); |
1736 | 1743 |
1737 // Get function and call it, if possible. | 1744 // Get function and call it, if possible. |
1738 __ lw(T0, Address(T0, target_offset)); | 1745 __ lw(T0, Address(T0, target_offset)); |
1739 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); | 1746 __ lw(CODE_REG, FieldAddress(T0, Function::code_offset())); |
1740 __ lw(T4, FieldAddress(T0, Function::entry_point_offset())); | 1747 __ lw(T4, FieldAddress(T0, Function::entry_point_offset())); |
(...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2414 } | 2421 } |
2415 | 2422 |
2416 | 2423 |
2417 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2424 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
2418 __ break_(0); | 2425 __ break_(0); |
2419 } | 2426 } |
2420 | 2427 |
2421 } // namespace dart | 2428 } // namespace dart |
2422 | 2429 |
2423 #endif // defined TARGET_ARCH_MIPS | 2430 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |