Chromium Code Reviews| 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: xxx must be preserved if 'not_smi_or_overflow' is jumped to. | |
|
Cutch
2014/08/15 21:23:28
xxx?
zra
2014/08/15 21:45:08
Should be R5 as on ARM.
srdjan
2014/08/15 21:49:00
R6.
zra
2014/08/15 22:12:33
Ah, right, sorry.
srdjan
2014/08/18 20:40:27
You are right: R5 :-).
| |
| 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 Label done, is_true; | |
|
zra
2014/08/15 21:45:08
Using conditional select:
__ CompareRegisters(R0,
srdjan
2014/08/18 20:40:27
Done.
| |
| 1347 __ cmp(R0, Operand(R1)); | |
| 1348 __ b(&is_true, EQ); | |
| 1349 __ LoadObject(R0, Bool::False(), PP); | |
| 1350 __ b(&done); | |
| 1351 __ Bind(&is_true); | |
| 1352 __ LoadObject(R0, Bool::True(), PP); | |
| 1353 __ Bind(&done); | |
| 1354 break; | |
| 1355 } | |
| 1356 default: UNIMPLEMENTED(); | |
| 1357 } | |
| 1358 | |
| 1359 // R5: IC data object (preserved). | |
| 1360 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP); | |
| 1361 // R6: ic_data_array with check entries: classes and target functions. | |
| 1362 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP); | |
| 1363 // R6: points directly to the first ic data array element. | |
| 1364 #ifdef DEBUG | |
| 1365 // Check that first entry is for Smi/Smi. | |
| 1366 Label error, ok; | |
| 1367 const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid)); | |
| 1368 __ ldr(R1, Address(R6, 0)); | |
| 1369 __ CompareImmediate(R1, imm_smi_cid, kNoPP); | |
| 1370 __ b(&error, NE); | |
| 1371 __ ldr(R1, Address(R6, kWordSize)); | |
| 1372 __ CompareImmediate(R1, imm_smi_cid, kNoPP); | |
| 1373 __ b(&ok, EQ); | |
| 1374 __ Bind(&error); | |
|
zra
2014/08/15 21:45:08
Same comment as on ARM.
srdjan
2014/08/18 20:40:27
Ditto.
| |
| 1375 __ Stop("Incorrect IC data"); | |
| 1376 __ Bind(&ok); | |
| 1377 #endif | |
| 1378 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | |
| 1379 // Update counter. | |
| 1380 __ LoadFromOffset(R1, R6, count_offset, kNoPP); | |
| 1381 __ adds(R1, R1, Operand(Smi::RawValue(1))); | |
| 1382 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue), kNoPP); | |
| 1383 __ csel(R1, R2, R1, VS); // Overflow. | |
| 1384 __ StoreToOffset(R1, R6, count_offset, kNoPP); | |
| 1385 | |
| 1386 __ ret(); | |
| 1387 } | |
| 1388 | |
| 1389 | |
| 1317 // Generate inline cache check for 'num_args'. | 1390 // Generate inline cache check for 'num_args'. |
| 1318 // LR: return address. | 1391 // LR: return address. |
| 1319 // R5: inline cache data object. | 1392 // R5: inline cache data object. |
| 1320 // Control flow: | 1393 // Control flow: |
| 1321 // - If receiver is null -> jump to IC miss. | 1394 // - If receiver is null -> jump to IC miss. |
| 1322 // - If receiver is Smi -> load Smi class. | 1395 // - If receiver is Smi -> load Smi class. |
| 1323 // - If receiver is not-Smi -> load receiver's class. | 1396 // - If receiver is not-Smi -> load receiver's class. |
| 1324 // - Check if 'num_args' (including receiver) match any IC data group. | 1397 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1325 // - Match found -> jump to target. | 1398 // - Match found -> jump to target. |
| 1326 // - Match not found -> jump to IC miss. | 1399 // - Match not found -> jump to IC miss. |
| 1327 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1400 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1328 Assembler* assembler, | 1401 Assembler* assembler, |
| 1329 intptr_t num_args, | 1402 intptr_t num_args, |
| 1330 const RuntimeEntry& handle_ic_miss) { | 1403 const RuntimeEntry& handle_ic_miss, |
| 1404 Token::Kind kind) { | |
| 1331 ASSERT(num_args > 0); | 1405 ASSERT(num_args > 0); |
| 1332 #if defined(DEBUG) | 1406 #if defined(DEBUG) |
| 1333 { Label ok; | 1407 { Label ok; |
| 1334 // Check that the IC data array has NumArgsTested() == num_args. | 1408 // Check that the IC data array has NumArgsTested() == num_args. |
| 1335 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1409 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1336 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1410 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 1337 kNoPP, kUnsignedWord); | 1411 kNoPP, kUnsignedWord); |
| 1338 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1412 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1339 __ andi(R6, R6, ICData::NumArgsTestedMask()); | 1413 __ andi(R6, R6, ICData::NumArgsTestedMask()); |
| 1340 __ CompareImmediate(R6, num_args, kNoPP); | 1414 __ CompareImmediate(R6, num_args, kNoPP); |
| 1341 __ b(&ok, EQ); | 1415 __ b(&ok, EQ); |
| 1342 __ Stop("Incorrect stub for IC data"); | 1416 __ Stop("Incorrect stub for IC data"); |
| 1343 __ Bind(&ok); | 1417 __ Bind(&ok); |
| 1344 } | 1418 } |
| 1345 #endif // DEBUG | 1419 #endif // DEBUG |
| 1346 | 1420 |
| 1347 Label stepping, done_stepping; | 1421 Label stepping, done_stepping; |
| 1348 // Check single stepping. | 1422 // Check single stepping. |
| 1349 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset(), kNoPP); | 1423 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset(), kNoPP); |
| 1350 __ LoadFromOffset( | 1424 __ LoadFromOffset( |
| 1351 R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte); | 1425 R6, R6, Isolate::single_step_offset(), kNoPP, kUnsignedByte); |
| 1352 __ CompareRegisters(R6, ZR); | 1426 __ CompareRegisters(R6, ZR); |
| 1353 __ b(&stepping, NE); | 1427 __ b(&stepping, NE); |
| 1354 __ Bind(&done_stepping); | 1428 __ Bind(&done_stepping); |
| 1355 | 1429 |
| 1430 if (kind != Token::kILLEGAL) { | |
| 1431 Label not_smi_or_overflow; | |
| 1432 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | |
| 1433 __ Bind(¬_smi_or_overflow); | |
| 1434 } | |
| 1435 | |
| 1356 // Load arguments descriptor into R4. | 1436 // Load arguments descriptor into R4. |
| 1357 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset(), kNoPP); | 1437 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset(), kNoPP); |
| 1358 // Loop that checks if there is an IC data match. | 1438 // Loop that checks if there is an IC data match. |
| 1359 Label loop, update, test, found; | 1439 Label loop, update, test, found; |
| 1360 // R5: IC data object (preserved). | 1440 // R5: IC data object (preserved). |
| 1361 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP); | 1441 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset(), kNoPP); |
| 1362 // R6: ic_data_array with check entries: classes and target functions. | 1442 // R6: ic_data_array with check entries: classes and target functions. |
| 1363 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP); | 1443 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag, kNoPP); |
| 1364 // R6: points directly to the first ic data array element. | 1444 // R6: points directly to the first ic data array element. |
| 1365 | 1445 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1482 // LR: return address. | 1562 // LR: return address. |
| 1483 // R5: inline cache data object. | 1563 // R5: inline cache data object. |
| 1484 // Inline cache data object structure: | 1564 // Inline cache data object structure: |
| 1485 // 0: function-name | 1565 // 0: function-name |
| 1486 // 1: N, number of arguments checked. | 1566 // 1: N, number of arguments checked. |
| 1487 // 2 .. (length - 1): group of checks, each check containing: | 1567 // 2 .. (length - 1): group of checks, each check containing: |
| 1488 // - N classes. | 1568 // - N classes. |
| 1489 // - 1 target function. | 1569 // - 1 target function. |
| 1490 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1570 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1491 GenerateUsageCounterIncrement(assembler, R6); | 1571 GenerateUsageCounterIncrement(assembler, R6); |
| 1492 GenerateNArgsCheckInlineCacheStub( | 1572 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1493 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1573 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1494 } | 1574 } |
| 1495 | 1575 |
| 1496 | 1576 |
| 1497 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1577 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1498 GenerateUsageCounterIncrement(assembler, R6); | 1578 GenerateUsageCounterIncrement(assembler, R6); |
| 1499 GenerateNArgsCheckInlineCacheStub( | 1579 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1500 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1580 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1501 } | 1581 } |
| 1502 | 1582 |
| 1503 | 1583 |
| 1504 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1584 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1505 GenerateUsageCounterIncrement(assembler, R6); | 1585 GenerateUsageCounterIncrement(assembler, R6); |
| 1506 GenerateNArgsCheckInlineCacheStub( | 1586 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1507 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1587 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1588 } | |
| 1589 | |
| 1590 | |
| 1591 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { | |
| 1592 GenerateUsageCounterIncrement(assembler, R6); | |
| 1593 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1594 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); | |
| 1595 } | |
| 1596 | |
| 1597 | |
| 1598 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { | |
| 1599 GenerateUsageCounterIncrement(assembler, R6); | |
| 1600 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1601 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); | |
| 1602 } | |
| 1603 | |
| 1604 | |
| 1605 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { | |
| 1606 GenerateUsageCounterIncrement(assembler, R6); | |
| 1607 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1608 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); | |
| 1508 } | 1609 } |
| 1509 | 1610 |
| 1510 | 1611 |
| 1511 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1612 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1512 Assembler* assembler) { | 1613 Assembler* assembler) { |
| 1513 GenerateOptimizedUsageCounterIncrement(assembler); | 1614 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1514 GenerateNArgsCheckInlineCacheStub( | 1615 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1515 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1616 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1516 } | 1617 } |
| 1517 | 1618 |
| 1518 | 1619 |
| 1519 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1620 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1520 Assembler* assembler) { | 1621 Assembler* assembler) { |
| 1521 GenerateOptimizedUsageCounterIncrement(assembler); | 1622 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1522 GenerateNArgsCheckInlineCacheStub( | 1623 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1523 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1624 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1524 } | 1625 } |
| 1525 | 1626 |
| 1526 | 1627 |
| 1527 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1628 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1528 Assembler* assembler) { | 1629 Assembler* assembler) { |
| 1529 GenerateOptimizedUsageCounterIncrement(assembler); | 1630 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1530 GenerateNArgsCheckInlineCacheStub( | 1631 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1531 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1632 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1532 } | 1633 } |
| 1533 | 1634 |
| 1534 | 1635 |
| 1535 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1636 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1536 GenerateNArgsCheckInlineCacheStub( | 1637 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1537 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1638 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1538 } | 1639 } |
| 1539 | 1640 |
| 1540 | 1641 |
| 1541 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1642 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1542 GenerateUsageCounterIncrement(assembler, R6); | 1643 GenerateUsageCounterIncrement(assembler, R6); |
| 1543 #if defined(DEBUG) | 1644 #if defined(DEBUG) |
| 1544 { Label ok; | 1645 { Label ok; |
| 1545 // Check that the IC data array has NumArgsTested() == 0. | 1646 // Check that the IC data array has NumArgsTested() == 0. |
| 1546 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1647 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1547 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1648 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1597 // R0: function. | 1698 // R0: function. |
| 1598 // R2: target instructons. | 1699 // R2: target instructons. |
| 1599 __ AddImmediate( | 1700 __ AddImmediate( |
| 1600 R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoPP); | 1701 R2, R2, Instructions::HeaderSize() - kHeapObjectTag, kNoPP); |
| 1601 __ br(R2); | 1702 __ br(R2); |
| 1602 } | 1703 } |
| 1603 | 1704 |
| 1604 | 1705 |
| 1605 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1706 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1606 GenerateUsageCounterIncrement(assembler, R6); | 1707 GenerateUsageCounterIncrement(assembler, R6); |
| 1607 GenerateNArgsCheckInlineCacheStub( | 1708 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1608 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); | 1709 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1609 } | 1710 } |
| 1610 | 1711 |
| 1611 | 1712 |
| 1612 // Stub for compiling a function and jumping to the compiled code. | 1713 // Stub for compiling a function and jumping to the compiled code. |
| 1613 // R5: IC-Data (for methods). | 1714 // R5: IC-Data (for methods). |
| 1614 // R4: Arguments descriptor. | 1715 // R4: Arguments descriptor. |
| 1615 // R0: Function. | 1716 // R0: Function. |
| 1616 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1717 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1617 // Preserve arg desc. and IC data object. | 1718 // Preserve arg desc. and IC data object. |
| 1618 __ EnterStubFrame(); | 1719 __ EnterStubFrame(); |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1956 const Register right = R0; | 2057 const Register right = R0; |
| 1957 __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP); | 2058 __ LoadFromOffset(left, SP, 1 * kWordSize, kNoPP); |
| 1958 __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP); | 2059 __ LoadFromOffset(right, SP, 0 * kWordSize, kNoPP); |
| 1959 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 2060 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1960 __ ret(); | 2061 __ ret(); |
| 1961 } | 2062 } |
| 1962 | 2063 |
| 1963 } // namespace dart | 2064 } // namespace dart |
| 1964 | 2065 |
| 1965 #endif // defined TARGET_ARCH_ARM64 | 2066 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |