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

Side by Side Diff: runtime/vm/stub_code_x64.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) 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_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 1218 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, 1229 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
1230 Register temp_reg) { 1230 Register temp_reg) {
1231 Register ic_reg = RBX; 1231 Register ic_reg = RBX;
1232 Register func_reg = temp_reg; 1232 Register func_reg = temp_reg;
1233 ASSERT(ic_reg != func_reg); 1233 ASSERT(ic_reg != func_reg);
1234 __ movq(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); 1234 __ movq(func_reg, FieldAddress(ic_reg, ICData::owner_offset()));
1235 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); 1235 __ incl(FieldAddress(func_reg, Function::usage_counter_offset()));
1236 } 1236 }
1237 1237
1238 1238
1239 // Note: RBX must be preserved.
1240 // Attempt a quick Smi operation for known operations ('kind'). The ICData
1241 // must have been primed with a Smi/Smi check that will be used for counting
1242 // the invocations.
1243 static void EmitFastSmiOp(Assembler* assembler,
1244 Token::Kind kind,
1245 intptr_t num_args,
1246 Label* not_smi_or_overflow) {
1247 if (FLAG_throw_on_javascript_int_overflow) {
1248 // The overflow check is more complex than implemented below.
1249 return;
1250 }
1251 ASSERT(num_args == 2);
1252 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Right
1253 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left.
1254 __ movq(R12, RCX);
1255 __ orq(R12, RAX);
1256 __ testq(R12, Immediate(kSmiTagMask));
1257 __ j(NOT_ZERO, not_smi_or_overflow, Assembler::kNearJump);
1258 switch (kind) {
1259 case Token::kADD: {
1260 __ addq(RAX, RCX);
1261 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump);
1262 break;
1263 }
1264 case Token::kSUB: {
1265 __ subq(RAX, RCX);
1266 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump);
1267 break;
1268 }
1269 case Token::kEQ: {
1270 Label done, is_true;
1271 __ cmpq(RAX, RCX);
1272 __ j(EQUAL, &is_true, Assembler::kNearJump);
1273 __ LoadObject(RAX, Bool::False(), PP);
1274 __ jmp(&done, Assembler::kNearJump);
1275 __ Bind(&is_true);
1276 __ LoadObject(RAX, Bool::True(), PP);
1277 __ Bind(&done);
1278 break;
1279 }
1280 default: UNIMPLEMENTED();
1281 }
1282
1283 // RBX: IC data object (preserved).
1284 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset()));
1285 // R12: ic_data_array with check entries: classes and target functions.
1286 __ leaq(R12, FieldAddress(R12, Array::data_offset()));
1287 // R12: points directly to the first ic data array element.
1288 #ifdef DEBUG
1289 // Check that first entry is for Smi/Smi.
1290 Label error, ok;
1291 const Immediate& imm_smi_cid =
1292 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid)));
1293 __ cmpq(Address(R12, 0 * kWordSize), imm_smi_cid);
1294 __ j(NOT_EQUAL, &error, Assembler::kNearJump);
1295 __ cmpq(Address(R12, 1 * kWordSize), imm_smi_cid);
1296 __ j(EQUAL, &ok, Assembler::kNearJump);
1297 __ Bind(&error);
zra 2014/08/15 21:45:09 Same comment as on ARM.
1298 __ Stop("Incorrect IC data");
1299 __ Bind(&ok);
1300 #endif
1301
1302 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1303 // Update counter.
1304 __ movq(R8, Address(R12, count_offset));
1305 __ addq(R8, Immediate(Smi::RawValue(1)));
1306 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1307 __ cmovnoq(R9, R8);
1308 __ movq(Address(R12, count_offset), R9);
1309
1310 __ ret();
1311 }
1312
1313
1239 // Generate inline cache check for 'num_args'. 1314 // Generate inline cache check for 'num_args'.
1240 // RBX: Inline cache data object. 1315 // RBX: Inline cache data object.
1241 // TOS(0): return address 1316 // TOS(0): return address
1242 // Control flow: 1317 // Control flow:
1243 // - If receiver is null -> jump to IC miss. 1318 // - If receiver is null -> jump to IC miss.
1244 // - If receiver is Smi -> load Smi class. 1319 // - If receiver is Smi -> load Smi class.
1245 // - If receiver is not-Smi -> load receiver's class. 1320 // - If receiver is not-Smi -> load receiver's class.
1246 // - Check if 'num_args' (including receiver) match any IC data group. 1321 // - Check if 'num_args' (including receiver) match any IC data group.
1247 // - Match found -> jump to target. 1322 // - Match found -> jump to target.
1248 // - Match not found -> jump to IC miss. 1323 // - Match not found -> jump to IC miss.
1249 void StubCode::GenerateNArgsCheckInlineCacheStub( 1324 void StubCode::GenerateNArgsCheckInlineCacheStub(
1250 Assembler* assembler, 1325 Assembler* assembler,
1251 intptr_t num_args, 1326 intptr_t num_args,
1252 const RuntimeEntry& handle_ic_miss) { 1327 const RuntimeEntry& handle_ic_miss,
1328 Token::Kind kind) {
1253 ASSERT(num_args > 0); 1329 ASSERT(num_args > 0);
1254 #if defined(DEBUG) 1330 #if defined(DEBUG)
1255 { Label ok; 1331 { Label ok;
1256 // Check that the IC data array has NumArgsTested() == num_args. 1332 // Check that the IC data array has NumArgsTested() == num_args.
1257 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. 1333 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'.
1258 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset())); 1334 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset()));
1259 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. 1335 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed.
1260 __ andq(RCX, Immediate(ICData::NumArgsTestedMask())); 1336 __ andq(RCX, Immediate(ICData::NumArgsTestedMask()));
1261 __ cmpq(RCX, Immediate(num_args)); 1337 __ cmpq(RCX, Immediate(num_args));
1262 __ j(EQUAL, &ok, Assembler::kNearJump); 1338 __ j(EQUAL, &ok, Assembler::kNearJump);
1263 __ Stop("Incorrect stub for IC data"); 1339 __ Stop("Incorrect stub for IC data");
1264 __ Bind(&ok); 1340 __ Bind(&ok);
1265 } 1341 }
1266 #endif // DEBUG 1342 #endif // DEBUG
1267 1343
1268 Label stepping, done_stepping; 1344 Label stepping, done_stepping;
1269 // Check single stepping. 1345 // Check single stepping.
1270 __ movq(RAX, FieldAddress(CTX, Context::isolate_offset())); 1346 __ movq(RAX, FieldAddress(CTX, Context::isolate_offset()));
1271 __ cmpb(Address(RAX, Isolate::single_step_offset()), Immediate(0)); 1347 __ cmpb(Address(RAX, Isolate::single_step_offset()), Immediate(0));
1272 __ j(NOT_EQUAL, &stepping); 1348 __ j(NOT_EQUAL, &stepping);
1273 __ Bind(&done_stepping); 1349 __ Bind(&done_stepping);
1274 1350
1351 if (kind != Token::kILLEGAL) {
1352 Label not_smi_or_overflow;
1353 EmitFastSmiOp(assembler, kind, num_args, &not_smi_or_overflow);
1354 __ Bind(&not_smi_or_overflow);
1355 }
1356
1275 // Load arguments descriptor into R10. 1357 // Load arguments descriptor into R10.
1276 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); 1358 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
1277 // Loop that checks if there is an IC data match. 1359 // Loop that checks if there is an IC data match.
1278 Label loop, update, test, found; 1360 Label loop, update, test, found;
1279 // RBX: IC data object (preserved). 1361 // RBX: IC data object (preserved).
1280 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); 1362 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset()));
1281 // R12: ic_data_array with check entries: classes and target functions. 1363 // R12: ic_data_array with check entries: classes and target functions.
1282 __ leaq(R12, FieldAddress(R12, Array::data_offset())); 1364 __ leaq(R12, FieldAddress(R12, Array::data_offset()));
1283 // R12: points directly to the first ic data array element. 1365 // R12: points directly to the first ic data array element.
1284 1366
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1389 // RBX: Inline cache data object. 1471 // RBX: Inline cache data object.
1390 // TOS(0): Return address. 1472 // TOS(0): Return address.
1391 // Inline cache data object structure: 1473 // Inline cache data object structure:
1392 // 0: function-name 1474 // 0: function-name
1393 // 1: N, number of arguments checked. 1475 // 1: N, number of arguments checked.
1394 // 2 .. (length - 1): group of checks, each check containing: 1476 // 2 .. (length - 1): group of checks, each check containing:
1395 // - N classes. 1477 // - N classes.
1396 // - 1 target function. 1478 // - 1 target function.
1397 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { 1479 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
1398 GenerateUsageCounterIncrement(assembler, RCX); 1480 GenerateUsageCounterIncrement(assembler, RCX);
1399 GenerateNArgsCheckInlineCacheStub( 1481 GenerateNArgsCheckInlineCacheStub(assembler, 1,
1400 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); 1482 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1401 } 1483 }
1402 1484
1403 1485
1404 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { 1486 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
1405 GenerateUsageCounterIncrement(assembler, RCX); 1487 GenerateUsageCounterIncrement(assembler, RCX);
1406 GenerateNArgsCheckInlineCacheStub( 1488 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1407 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); 1489 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
1408 } 1490 }
1409 1491
1410 1492
1411 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { 1493 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) {
1412 GenerateUsageCounterIncrement(assembler, RCX); 1494 GenerateUsageCounterIncrement(assembler, RCX);
1413 GenerateNArgsCheckInlineCacheStub( 1495 GenerateNArgsCheckInlineCacheStub(assembler, 3,
1414 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); 1496 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL);
1415 } 1497 }
1416 1498
1499
1500 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) {
1501 GenerateUsageCounterIncrement(assembler, RCX);
1502 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1503 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD);
1504 }
1505
1506
1507 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) {
1508 GenerateUsageCounterIncrement(assembler, RCX);
1509 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1510 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB);
1511 }
1512
1513
1514 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) {
1515 GenerateUsageCounterIncrement(assembler, RCX);
1516 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1517 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ);
1518 }
1519
1520
1417 // Use inline cache data array to invoke the target or continue in inline 1521 // Use inline cache data array to invoke the target or continue in inline
1418 // cache miss handler. Stub for 1-argument check (receiver class). 1522 // cache miss handler. Stub for 1-argument check (receiver class).
1419 // RDI: function which counter needs to be incremented. 1523 // RDI: function which counter needs to be incremented.
1420 // RBX: Inline cache data object. 1524 // RBX: Inline cache data object.
1421 // TOS(0): Return address. 1525 // TOS(0): Return address.
1422 // Inline cache data object structure: 1526 // Inline cache data object structure:
1423 // 0: function-name 1527 // 0: function-name
1424 // 1: N, number of arguments checked. 1528 // 1: N, number of arguments checked.
1425 // 2 .. (length - 1): group of checks, each check containing: 1529 // 2 .. (length - 1): group of checks, each check containing:
1426 // - N classes. 1530 // - N classes.
1427 // - 1 target function. 1531 // - 1 target function.
1428 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( 1532 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub(
1429 Assembler* assembler) { 1533 Assembler* assembler) {
1430 GenerateOptimizedUsageCounterIncrement(assembler); 1534 GenerateOptimizedUsageCounterIncrement(assembler);
1431 GenerateNArgsCheckInlineCacheStub( 1535 GenerateNArgsCheckInlineCacheStub(assembler, 1,
1432 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); 1536 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1433 } 1537 }
1434 1538
1435 1539
1436 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( 1540 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub(
1437 Assembler* assembler) { 1541 Assembler* assembler) {
1438 GenerateOptimizedUsageCounterIncrement(assembler); 1542 GenerateOptimizedUsageCounterIncrement(assembler);
1439 GenerateNArgsCheckInlineCacheStub( 1543 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1440 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); 1544 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
1441 } 1545 }
1442 1546
1443 1547
1444 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( 1548 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub(
1445 Assembler* assembler) { 1549 Assembler* assembler) {
1446 GenerateOptimizedUsageCounterIncrement(assembler); 1550 GenerateOptimizedUsageCounterIncrement(assembler);
1447 GenerateNArgsCheckInlineCacheStub( 1551 GenerateNArgsCheckInlineCacheStub(assembler, 3,
1448 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); 1552 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL);
1449 } 1553 }
1450 1554
1451 1555
1452 // Do not count as no type feedback is collected. 1556 // Do not count as no type feedback is collected.
1453 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { 1557 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) {
1454 GenerateNArgsCheckInlineCacheStub( 1558 GenerateNArgsCheckInlineCacheStub(assembler, 1,
1455 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); 1559 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1456 } 1560 }
1457 1561
1458 1562
1459 // Intermediary stub between a static call and its target. ICData contains 1563 // Intermediary stub between a static call and its target. ICData contains
1460 // the target function and the call count. 1564 // the target function and the call count.
1461 // RBX: ICData 1565 // RBX: ICData
1462 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { 1566 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
1463 GenerateUsageCounterIncrement(assembler, RCX); 1567 GenerateUsageCounterIncrement(assembler, RCX);
1464 #if defined(DEBUG) 1568 #if defined(DEBUG)
1465 { Label ok; 1569 { Label ok;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1511 __ movq(RAX, Address(R12, target_offset)); 1615 __ movq(RAX, Address(R12, target_offset));
1512 __ movq(RCX, FieldAddress(RAX, Function::instructions_offset())); 1616 __ movq(RCX, FieldAddress(RAX, Function::instructions_offset()));
1513 // RCX: Target instructions. 1617 // RCX: Target instructions.
1514 __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); 1618 __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
1515 __ jmp(RCX); 1619 __ jmp(RCX);
1516 } 1620 }
1517 1621
1518 1622
1519 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { 1623 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
1520 GenerateUsageCounterIncrement(assembler, RCX); 1624 GenerateUsageCounterIncrement(assembler, RCX);
1521 GenerateNArgsCheckInlineCacheStub( 1625 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1522 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); 1626 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
1523 } 1627 }
1524 1628
1525 1629
1526 // Stub for compiling a function and jumping to the compiled code. 1630 // Stub for compiling a function and jumping to the compiled code.
1527 // RCX: IC-Data (for methods). 1631 // RCX: IC-Data (for methods).
1528 // R10: Arguments descriptor. 1632 // R10: Arguments descriptor.
1529 // RAX: Function. 1633 // RAX: Function.
1530 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { 1634 void StubCode::GenerateLazyCompileStub(Assembler* assembler) {
1531 __ EnterStubFrame(); 1635 __ EnterStubFrame();
1532 __ pushq(R10); // Preserve arguments descriptor array. 1636 __ pushq(R10); // Preserve arguments descriptor array.
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
1899 2003
1900 __ movq(left, Address(RSP, 2 * kWordSize)); 2004 __ movq(left, Address(RSP, 2 * kWordSize));
1901 __ movq(right, Address(RSP, 1 * kWordSize)); 2005 __ movq(right, Address(RSP, 1 * kWordSize));
1902 GenerateIdenticalWithNumberCheckStub(assembler, left, right); 2006 GenerateIdenticalWithNumberCheckStub(assembler, left, right);
1903 __ ret(); 2007 __ ret();
1904 } 2008 }
1905 2009
1906 } // namespace dart 2010 } // namespace dart
1907 2011
1908 #endif // defined TARGET_ARCH_X64 2012 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698