| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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 1296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1307 ASSERT(temp_reg == R6); | 1307 ASSERT(temp_reg == R6); |
| 1308 __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset(), kNoPP); | 1308 __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset(), kNoPP); |
| 1309 __ LoadFieldFromOffset( | 1309 __ LoadFieldFromOffset( |
| 1310 R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord); | 1310 R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord); |
| 1311 __ AddImmediate(R7, R7, 1, kNoPP); | 1311 __ AddImmediate(R7, R7, 1, kNoPP); |
| 1312 __ StoreFieldToOffset( | 1312 __ StoreFieldToOffset( |
| 1313 R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord); | 1313 R7, func_reg, Function::usage_counter_offset(), kNoPP, kWord); |
| 1314 } | 1314 } |
| 1315 | 1315 |
| 1316 | 1316 |
| 1317 // Note: R5 must be preserved. |
| 1318 // Attempt a quick Smi operation for known operations ('kind'). The ICData |
| 1319 // must have been primed with a Smi/Smi check that will be used for counting |
| 1320 // the invocations. |
| 1321 static void EmitFastSmiOp(Assembler* assembler, |
| 1322 Token::Kind kind, |
| 1323 intptr_t num_args, |
| 1324 Label* not_smi_or_overflow) { |
| 1325 if (FLAG_throw_on_javascript_int_overflow) { |
| 1326 // The overflow check is more complex than implemented below. |
| 1327 return; |
| 1328 } |
| 1329 __ ldr(R0, Address(SP, + 0 * kWordSize)); // Right. |
| 1330 __ ldr(R1, Address(SP, + 1 * kWordSize)); // Left. |
| 1331 __ orr(TMP, R0, Operand(R1)); |
| 1332 __ tsti(TMP, kSmiTagMask); |
| 1333 __ b(not_smi_or_overflow, NE); |
| 1334 switch (kind) { |
| 1335 case Token::kADD: { |
| 1336 __ adds(R0, R1, Operand(R0)); // Adds. |
| 1337 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1338 break; |
| 1339 } |
| 1340 case Token::kSUB: { |
| 1341 __ subs(R0, R1, Operand(R0)); // Subtract. |
| 1342 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1343 break; |
| 1344 } |
| 1345 case Token::kEQ: { |
| 1346 __ CompareRegisters(R0, R1); |
| 1347 __ LoadObject(R0, Bool::True(), PP); |
| 1348 __ LoadObject(R1, Bool::False(), PP); |
| 1349 __ csel(R0, R1, R0, NE); |
| 1350 break; |
| 1351 } |
| 1352 default: UNIMPLEMENTED(); |
| 1353 } |
| 1354 |
| 1355 // R5: IC data object (preserved). |
| 1356 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP); |
| 1357 // R6: ic_data_array with check entries: classes and target functions. |
| 1358 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP); |
| 1359 // R6: points directly to the first ic data array element. |
| 1360 #if defined(DEBUG) |
| 1361 // Check that first entry is for Smi/Smi. |
| 1362 Label error, ok; |
| 1363 const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid)); |
| 1364 __ ldr(R1, Address(R6, 0)); |
| 1365 __ CompareImmediate(R1, imm_smi_cid, kNoPP); |
| 1366 __ b(&error, NE); |
| 1367 __ ldr(R1, Address(R6, kWordSize)); |
| 1368 __ CompareImmediate(R1, imm_smi_cid, kNoPP); |
| 1369 __ b(&ok, EQ); |
| 1370 __ Bind(&error); |
| 1371 __ Stop("Incorrect IC data"); |
| 1372 __ Bind(&ok); |
| 1373 #endif |
| 1374 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1375 // Update counter. |
| 1376 __ LoadFromOffset(R1, R6, count_offset, kNoPP); |
| 1377 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1378 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue), kNoPP); |
| 1379 __ csel(R1, R2, R1, VS); // Overflow. |
| 1380 __ StoreToOffset(R1, R6, count_offset, kNoPP); |
| 1381 |
| 1382 __ ret(); |
| 1383 } |
| 1384 |
| 1385 |
| 1317 // Generate inline cache check for 'num_args'. | 1386 // Generate inline cache check for 'num_args'. |
| 1318 // LR: return address. | 1387 // LR: return address. |
| 1319 // R5: inline cache data object. | 1388 // R5: inline cache data object. |
| 1320 // Control flow: | 1389 // Control flow: |
| 1321 // - If receiver is null -> jump to IC miss. | 1390 // - If receiver is null -> jump to IC miss. |
| 1322 // - If receiver is Smi -> load Smi class. | 1391 // - If receiver is Smi -> load Smi class. |
| 1323 // - If receiver is not-Smi -> load receiver's class. | 1392 // - If receiver is not-Smi -> load receiver's class. |
| 1324 // - Check if 'num_args' (including receiver) match any IC data group. | 1393 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1325 // - Match found -> jump to target. | 1394 // - Match found -> jump to target. |
| 1326 // - Match not found -> jump to IC miss. | 1395 // - Match not found -> jump to IC miss. |
| 1327 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1396 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1328 Assembler* assembler, | 1397 Assembler* assembler, |
| 1329 intptr_t num_args, | 1398 intptr_t num_args, |
| 1330 const RuntimeEntry& handle_ic_miss) { | 1399 const RuntimeEntry& handle_ic_miss, |
| 1400 Token::Kind kind) { |
| 1331 ASSERT(num_args > 0); | 1401 ASSERT(num_args > 0); |
| 1332 #if defined(DEBUG) | 1402 #if defined(DEBUG) |
| 1333 { Label ok; | 1403 { Label ok; |
| 1334 // Check that the IC data array has NumArgsTested() == num_args. | 1404 // Check that the IC data array has NumArgsTested() == num_args. |
| 1335 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1405 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1336 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1406 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 1337 kNoPP, kUnsignedWord); | 1407 kNoPP, kUnsignedWord); |
| 1338 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1408 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1339 __ andi(R6, R6, ICData::NumArgsTestedMask()); | 1409 __ andi(R6, R6, ICData::NumArgsTestedMask()); |
| 1340 __ CompareImmediate(R6, num_args, kNoPP); | 1410 __ CompareImmediate(R6, num_args, kNoPP); |
| 1341 __ b(&ok, EQ); | 1411 __ b(&ok, EQ); |
| 1342 __ Stop("Incorrect stub for IC data"); | 1412 __ Stop("Incorrect stub for IC data"); |
| 1343 __ Bind(&ok); | 1413 __ Bind(&ok); |
| 1344 } | 1414 } |
| 1345 #endif // DEBUG | 1415 #endif // DEBUG |
| 1346 | 1416 |
| 1347 Label stepping, done_stepping; | 1417 Label stepping, done_stepping; |
| 1348 // Check single stepping. | 1418 // Check single stepping. |
| 1349 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset(), kNoPP); | 1419 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset(), kNoPP); |
| 1350 __ LoadFromOffset( | 1420 __ LoadFromOffset( |
| 1351 R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte); | 1421 R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte); |
| 1352 __ CompareRegisters(R6, ZR); | 1422 __ CompareRegisters(R6, ZR); |
| 1353 __ b(&stepping, NE); | 1423 __ b(&stepping, NE); |
| 1354 __ Bind(&done_stepping); | 1424 __ Bind(&done_stepping); |
| 1355 | 1425 |
| 1426 if (kind != Token::kILLEGAL) { |
| 1427 Label not_smi_or_overflow; |
| 1428 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1429 __ Bind(¬_smi_or_overflow); |
| 1430 } |
| 1431 |
| 1356 // Load arguments descriptor into R4. | 1432 // Load arguments descriptor into R4. |
| 1357 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset(), kNoPP); | 1433 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset(), kNoPP); |
| 1358 // Loop that checks if there is an IC data match. | 1434 // Loop that checks if there is an IC data match. |
| 1359 Label loop, update, test, found; | 1435 Label loop, update, test, found; |
| 1360 // R5: IC data object (preserved). | 1436 // R5: IC data object (preserved). |
| 1361 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP); | 1437 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP); |
| 1362 // R6: ic_data_array with check entries: classes and target functions. | 1438 // R6: ic_data_array with check entries: classes and target functions. |
| 1363 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP); | 1439 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP); |
| 1364 // R6: points directly to the first ic data array element. | 1440 // R6: points directly to the first ic data array element. |
| 1365 | 1441 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1482 // LR: return address. | 1558 // LR: return address. |
| 1483 // R5: inline cache data object. | 1559 // R5: inline cache data object. |
| 1484 // Inline cache data object structure: | 1560 // Inline cache data object structure: |
| 1485 // 0: function-name | 1561 // 0: function-name |
| 1486 // 1: N, number of arguments checked. | 1562 // 1: N, number of arguments checked. |
| 1487 // 2 .. (length - 1): group of checks, each check containing: | 1563 // 2 .. (length - 1): group of checks, each check containing: |
| 1488 // - N classes. | 1564 // - N classes. |
| 1489 // - 1 target function. | 1565 // - 1 target function. |
| 1490 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1566 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1491 GenerateUsageCounterIncrement(assembler, R6); | 1567 GenerateUsageCounterIncrement(assembler, R6); |
| 1492 GenerateNArgsCheckInlineCacheStub( | 1568 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1493 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1569 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1494 } | 1570 } |
| 1495 | 1571 |
| 1496 | 1572 |
| 1497 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1573 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1498 GenerateUsageCounterIncrement(assembler, R6); | 1574 GenerateUsageCounterIncrement(assembler, R6); |
| 1499 GenerateNArgsCheckInlineCacheStub( | 1575 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1500 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1576 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1501 } | 1577 } |
| 1502 | 1578 |
| 1503 | 1579 |
| 1504 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1580 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1505 GenerateUsageCounterIncrement(assembler, R6); | 1581 GenerateUsageCounterIncrement(assembler, R6); |
| 1506 GenerateNArgsCheckInlineCacheStub( | 1582 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1507 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1583 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1584 } |
| 1585 |
| 1586 |
| 1587 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { |
| 1588 GenerateUsageCounterIncrement(assembler, R6); |
| 1589 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1590 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); |
| 1591 } |
| 1592 |
| 1593 |
| 1594 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { |
| 1595 GenerateUsageCounterIncrement(assembler, R6); |
| 1596 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1597 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); |
| 1598 } |
| 1599 |
| 1600 |
| 1601 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { |
| 1602 GenerateUsageCounterIncrement(assembler, R6); |
| 1603 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1604 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); |
| 1508 } | 1605 } |
| 1509 | 1606 |
| 1510 | 1607 |
| 1511 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1608 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1512 Assembler* assembler) { | 1609 Assembler* assembler) { |
| 1513 GenerateOptimizedUsageCounterIncrement(assembler); | 1610 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1514 GenerateNArgsCheckInlineCacheStub( | 1611 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1515 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1612 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1516 } | 1613 } |
| 1517 | 1614 |
| 1518 | 1615 |
| 1519 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1616 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1520 Assembler* assembler) { | 1617 Assembler* assembler) { |
| 1521 GenerateOptimizedUsageCounterIncrement(assembler); | 1618 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1522 GenerateNArgsCheckInlineCacheStub( | 1619 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1523 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1620 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1524 } | 1621 } |
| 1525 | 1622 |
| 1526 | 1623 |
| 1527 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1624 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1528 Assembler* assembler) { | 1625 Assembler* assembler) { |
| 1529 GenerateOptimizedUsageCounterIncrement(assembler); | 1626 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1530 GenerateNArgsCheckInlineCacheStub( | 1627 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1531 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1628 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1532 } | 1629 } |
| 1533 | 1630 |
| 1534 | 1631 |
| 1535 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1632 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1536 GenerateNArgsCheckInlineCacheStub( | 1633 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1537 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1634 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1538 } | 1635 } |
| 1539 | 1636 |
| 1540 | 1637 |
| 1541 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1638 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1542 GenerateUsageCounterIncrement(assembler, R6); | 1639 GenerateUsageCounterIncrement(assembler, R6); |
| 1543 #if defined(DEBUG) | 1640 #if defined(DEBUG) |
| 1544 { Label ok; | 1641 { Label ok; |
| 1545 // Check that the IC data array has NumArgsTested() == 0. | 1642 // Check that the IC data array has NumArgsTested() == 0. |
| 1546 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1643 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1547 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1644 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1598 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1695 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1599 __ Pop(R5); | 1696 __ Pop(R5); |
| 1600 __ LeaveStubFrame(); | 1697 __ LeaveStubFrame(); |
| 1601 __ b(&done_stepping); | 1698 __ b(&done_stepping); |
| 1602 } | 1699 } |
| 1603 | 1700 |
| 1604 | 1701 |
| 1605 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1702 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1606 GenerateUsageCounterIncrement(assembler, R6); | 1703 GenerateUsageCounterIncrement(assembler, R6); |
| 1607 GenerateNArgsCheckInlineCacheStub( | 1704 GenerateNArgsCheckInlineCacheStub( |
| 1608 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry); | 1705 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1609 } | 1706 } |
| 1610 | 1707 |
| 1611 | 1708 |
| 1612 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1709 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1613 GenerateUsageCounterIncrement(assembler, R6); | 1710 GenerateUsageCounterIncrement(assembler, R6); |
| 1614 GenerateNArgsCheckInlineCacheStub( | 1711 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1615 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); | 1712 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1616 } | 1713 } |
| 1617 | 1714 |
| 1618 | 1715 |
| 1619 // Stub for compiling a function and jumping to the compiled code. | 1716 // Stub for compiling a function and jumping to the compiled code. |
| 1620 // R5: IC-Data (for methods). | 1717 // R5: IC-Data (for methods). |
| 1621 // R4: Arguments descriptor. | 1718 // R4: Arguments descriptor. |
| 1622 // R0: Function. | 1719 // R0: Function. |
| 1623 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1720 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1624 // Preserve arg desc. and IC data object. | 1721 // Preserve arg desc. and IC data object. |
| 1625 __ EnterStubFrame(); | 1722 __ EnterStubFrame(); |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1969 const Register right = R0; | 2066 const Register right = R0; |
| 1970 __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP); | 2067 __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP); |
| 1971 __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP); | 2068 __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP); |
| 1972 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2069 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1973 __ ret(); | 2070 __ ret(); |
| 1974 } | 2071 } |
| 1975 | 2072 |
| 1976 } // namespace dart | 2073 } // namespace dart |
| 1977 | 2074 |
| 1978 #endif // defined TARGET_ARCH_ARM64 | 2075 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |