Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: runtime/vm/stub_code_arm64.cc

Issue 436643002: Faster IC stubs by specializing them for Binary Smi operations (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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, &not_smi_or_overflow);
1429 __ Bind(&not_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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698