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

Side by Side Diff: runtime/vm/stub_code_ia32.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_IA32) 6 #if defined(TARGET_ARCH_IA32)
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 1244 matching lines...) Expand 10 before | Expand all | Expand 10 after
1255 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, 1255 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
1256 Register temp_reg) { 1256 Register temp_reg) {
1257 Register ic_reg = ECX; 1257 Register ic_reg = ECX;
1258 Register func_reg = temp_reg; 1258 Register func_reg = temp_reg;
1259 ASSERT(ic_reg != func_reg); 1259 ASSERT(ic_reg != func_reg);
1260 __ movl(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); 1260 __ movl(func_reg, FieldAddress(ic_reg, ICData::owner_offset()));
1261 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); 1261 __ incl(FieldAddress(func_reg, Function::usage_counter_offset()));
1262 } 1262 }
1263 1263
1264 1264
1265 // Note: ECX must be preserved.
1266 // Attempt a quick Smi operation for known operations ('kind'). The ICData
1267 // must have been primed with a Smi/Smi check that will be used for counting
1268 // the invocations.
1269 static void EmitFastSmiOp(Assembler* assembler,
1270 Token::Kind kind,
1271 intptr_t num_args,
1272 Label* not_smi_or_overflow) {
1273 ASSERT(num_args == 2);
1274 __ movl(EDI, Address(ESP, + 1 * kWordSize)); // Right
1275 __ movl(EAX, Address(ESP, + 2 * kWordSize)); // Left
1276 __ movl(EBX, EDI);
1277 __ orl(EBX, EAX);
1278 __ testl(EBX, Immediate(kSmiTagMask));
1279 __ j(NOT_ZERO, not_smi_or_overflow, Assembler::kNearJump);
1280 switch (kind) {
1281 case Token::kADD: {
1282 __ addl(EAX, EDI);
1283 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump);
1284 break;
1285 }
1286 case Token::kSUB: {
1287 __ subl(EAX, EDI);
1288 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump);
1289 break;
1290 }
1291 case Token::kEQ: {
1292 Label done, is_true;
1293 __ cmpl(EAX, EDI);
1294 __ j(EQUAL, &is_true, Assembler::kNearJump);
1295 __ LoadObject(EAX, Bool::False());
1296 __ jmp(&done, Assembler::kNearJump);
1297 __ Bind(&is_true);
1298 __ LoadObject(EAX, Bool::True());
1299 __ Bind(&done);
1300 break;
1301 }
1302 default: UNIMPLEMENTED();
1303 }
1304
1305 // ECX: IC data object.
1306 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset()));
1307 // EBX: ic_data_array with check entries: classes and target functions.
1308 __ leal(EBX, FieldAddress(EBX, Array::data_offset()));
1309 #if defined(DEBUG)
1310 // Check that first entry is for Smi/Smi.
1311 Label error, ok;
1312 const Immediate& imm_smi_cid =
1313 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid)));
1314 __ cmpl(Address(EBX, 0 * kWordSize), imm_smi_cid);
1315 __ j(NOT_EQUAL, &error, Assembler::kNearJump);
1316 __ cmpl(Address(EBX, 1 * kWordSize), imm_smi_cid);
1317 __ j(EQUAL, &ok, Assembler::kNearJump);
1318 __ Bind(&error);
1319 __ Stop("Incorrect IC data");
1320 __ Bind(&ok);
1321 #endif
1322 // Update counter.
1323 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1324 __ movl(ECX, Address(EBX, count_offset));
1325 __ addl(ECX, Immediate(Smi::RawValue(1)));
1326 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
1327 __ cmovno(EDI, ECX);
1328 __ movl(Address(EBX, count_offset), EDI);
1329
1330 __ ret();
1331 }
1332
1333
1265 // Generate inline cache check for 'num_args'. 1334 // Generate inline cache check for 'num_args'.
1266 // ECX: Inline cache data object. 1335 // ECX: Inline cache data object.
1267 // TOS(0): return address 1336 // TOS(0): return address
1268 // Control flow: 1337 // Control flow:
1269 // - If receiver is null -> jump to IC miss. 1338 // - If receiver is null -> jump to IC miss.
1270 // - If receiver is Smi -> load Smi class. 1339 // - If receiver is Smi -> load Smi class.
1271 // - If receiver is not-Smi -> load receiver's class. 1340 // - If receiver is not-Smi -> load receiver's class.
1272 // - Check if 'num_args' (including receiver) match any IC data group. 1341 // - Check if 'num_args' (including receiver) match any IC data group.
1273 // - Match found -> jump to target. 1342 // - Match found -> jump to target.
1274 // - Match not found -> jump to IC miss. 1343 // - Match not found -> jump to IC miss.
1275 void StubCode::GenerateNArgsCheckInlineCacheStub( 1344 void StubCode::GenerateNArgsCheckInlineCacheStub(
1276 Assembler* assembler, 1345 Assembler* assembler,
1277 intptr_t num_args, 1346 intptr_t num_args,
1278 const RuntimeEntry& handle_ic_miss) { 1347 const RuntimeEntry& handle_ic_miss,
1348 Token::Kind kind) {
1279 ASSERT(num_args > 0); 1349 ASSERT(num_args > 0);
1280 #if defined(DEBUG) 1350 #if defined(DEBUG)
1281 { Label ok; 1351 { Label ok;
1282 // Check that the IC data array has NumArgsTested() == num_args. 1352 // Check that the IC data array has NumArgsTested() == num_args.
1283 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. 1353 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'.
1284 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset())); 1354 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset()));
1285 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. 1355 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed.
1286 __ andl(EBX, Immediate(ICData::NumArgsTestedMask())); 1356 __ andl(EBX, Immediate(ICData::NumArgsTestedMask()));
1287 __ cmpl(EBX, Immediate(num_args)); 1357 __ cmpl(EBX, Immediate(num_args));
1288 __ j(EQUAL, &ok, Assembler::kNearJump); 1358 __ j(EQUAL, &ok, Assembler::kNearJump);
1289 __ Stop("Incorrect stub for IC data"); 1359 __ Stop("Incorrect stub for IC data");
1290 __ Bind(&ok); 1360 __ Bind(&ok);
1291 } 1361 }
1292 #endif // DEBUG 1362 #endif // DEBUG
1293 1363
1294 Label stepping, done_stepping; 1364 Label stepping, done_stepping;
1295 // Check single stepping. 1365 // Check single stepping.
1296 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset())); 1366 __ movl(EAX, FieldAddress(CTX, Context::isolate_offset()));
1297 __ cmpb(Address(EAX, Isolate::single_step_offset()), Immediate(0)); 1367 __ cmpb(Address(EAX, Isolate::single_step_offset()), Immediate(0));
1298 __ j(NOT_EQUAL, &stepping); 1368 __ j(NOT_EQUAL, &stepping);
1299 __ Bind(&done_stepping); 1369 __ Bind(&done_stepping);
1300 1370
1371 if (kind != Token::kILLEGAL) {
1372 Label not_smi_or_overflow;
1373 EmitFastSmiOp(assembler, kind, num_args, &not_smi_or_overflow);
1374 __ Bind(&not_smi_or_overflow);
1375 }
1376
1301 // ECX: IC data object (preserved). 1377 // ECX: IC data object (preserved).
1302 // Load arguments descriptor into EDX. 1378 // Load arguments descriptor into EDX.
1303 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); 1379 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset()));
1304 // Loop that checks if there is an IC data match. 1380 // Loop that checks if there is an IC data match.
1305 Label loop, update, test, found; 1381 Label loop, update, test, found;
1306 // ECX: IC data object (preserved). 1382 // ECX: IC data object (preserved).
1307 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); 1383 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset()));
1308 // EBX: ic_data_array with check entries: classes and target functions. 1384 // EBX: ic_data_array with check entries: classes and target functions.
1309 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); 1385 __ leal(EBX, FieldAddress(EBX, Array::data_offset()));
1310 // EBX: points directly to the first ic data array element. 1386 // EBX: points directly to the first ic data array element.
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
1421 // ECX: Inline cache data object. 1497 // ECX: Inline cache data object.
1422 // TOS(0): Return address. 1498 // TOS(0): Return address.
1423 // Inline cache data object structure: 1499 // Inline cache data object structure:
1424 // 0: function-name 1500 // 0: function-name
1425 // 1: N, number of arguments checked. 1501 // 1: N, number of arguments checked.
1426 // 2 .. (length - 1): group of checks, each check containing: 1502 // 2 .. (length - 1): group of checks, each check containing:
1427 // - N classes. 1503 // - N classes.
1428 // - 1 target function. 1504 // - 1 target function.
1429 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { 1505 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
1430 GenerateUsageCounterIncrement(assembler, EBX); 1506 GenerateUsageCounterIncrement(assembler, EBX);
1431 GenerateNArgsCheckInlineCacheStub( 1507 GenerateNArgsCheckInlineCacheStub(assembler, 1,
1432 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); 1508 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1433 } 1509 }
1434 1510
1435 1511
1436 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { 1512 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
1437 GenerateUsageCounterIncrement(assembler, EBX); 1513 GenerateUsageCounterIncrement(assembler, EBX);
1438 GenerateNArgsCheckInlineCacheStub( 1514 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1439 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); 1515 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
1440 } 1516 }
1441 1517
1442 1518
1443 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { 1519 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) {
1444 GenerateUsageCounterIncrement(assembler, EBX); 1520 GenerateUsageCounterIncrement(assembler, EBX);
1445 GenerateNArgsCheckInlineCacheStub( 1521 GenerateNArgsCheckInlineCacheStub(assembler, 3,
1446 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); 1522 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL);
1523 }
1524
1525
1526 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) {
1527 GenerateUsageCounterIncrement(assembler, EBX);
1528 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1529 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD);
1530 }
1531
1532
1533 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) {
1534 GenerateUsageCounterIncrement(assembler, EBX);
1535 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1536 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB);
1537 }
1538
1539
1540 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) {
1541 GenerateUsageCounterIncrement(assembler, EBX);
1542 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1543 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ);
1447 } 1544 }
1448 1545
1449 1546
1450 // Use inline cache data array to invoke the target or continue in inline 1547 // Use inline cache data array to invoke the target or continue in inline
1451 // cache miss handler. Stub for 1-argument check (receiver class). 1548 // cache miss handler. Stub for 1-argument check (receiver class).
1452 // EDI: function which counter needs to be incremented. 1549 // EDI: function which counter needs to be incremented.
1453 // ECX: Inline cache data object. 1550 // ECX: Inline cache data object.
1454 // TOS(0): Return address. 1551 // TOS(0): Return address.
1455 // Inline cache data object structure: 1552 // Inline cache data object structure:
1456 // 0: function-name 1553 // 0: function-name
1457 // 1: N, number of arguments checked. 1554 // 1: N, number of arguments checked.
1458 // 2 .. (length - 1): group of checks, each check containing: 1555 // 2 .. (length - 1): group of checks, each check containing:
1459 // - N classes. 1556 // - N classes.
1460 // - 1 target function. 1557 // - 1 target function.
1461 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( 1558 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub(
1462 Assembler* assembler) { 1559 Assembler* assembler) {
1463 GenerateOptimizedUsageCounterIncrement(assembler); 1560 GenerateOptimizedUsageCounterIncrement(assembler);
1464 GenerateNArgsCheckInlineCacheStub( 1561 GenerateNArgsCheckInlineCacheStub(assembler, 1,
1465 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); 1562 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1466 } 1563 }
1467 1564
1468 1565
1469 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( 1566 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub(
1470 Assembler* assembler) { 1567 Assembler* assembler) {
1471 GenerateOptimizedUsageCounterIncrement(assembler); 1568 GenerateOptimizedUsageCounterIncrement(assembler);
1472 GenerateNArgsCheckInlineCacheStub( 1569 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1473 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); 1570 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
1474 } 1571 }
1475 1572
1476 1573
1477 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( 1574 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub(
1478 Assembler* assembler) { 1575 Assembler* assembler) {
1479 GenerateOptimizedUsageCounterIncrement(assembler); 1576 GenerateOptimizedUsageCounterIncrement(assembler);
1480 GenerateNArgsCheckInlineCacheStub( 1577 GenerateNArgsCheckInlineCacheStub(assembler, 3,
1481 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); 1578 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL);
1482 } 1579 }
1483 1580
1484 1581
1485 // Do not count as no type feedback is collected. 1582 // Do not count as no type feedback is collected.
1486 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { 1583 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) {
1487 GenerateNArgsCheckInlineCacheStub( 1584 GenerateNArgsCheckInlineCacheStub(assembler, 1,
1488 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); 1585 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1489 } 1586 }
1490 1587
1491 1588
1492 // Intermediary stub between a static call and its target. ICData contains 1589 // Intermediary stub between a static call and its target. ICData contains
1493 // the target function and the call count. 1590 // the target function and the call count.
1494 // ECX: ICData 1591 // ECX: ICData
1495 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { 1592 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) {
1496 GenerateUsageCounterIncrement(assembler, EBX); 1593 GenerateUsageCounterIncrement(assembler, EBX);
1497 1594
1498 #if defined(DEBUG) 1595 #if defined(DEBUG)
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1548 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); 1645 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0);
1549 __ popl(ECX); 1646 __ popl(ECX);
1550 __ LeaveFrame(); 1647 __ LeaveFrame();
1551 __ jmp(&done_stepping, Assembler::kNearJump); 1648 __ jmp(&done_stepping, Assembler::kNearJump);
1552 } 1649 }
1553 1650
1554 1651
1555 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { 1652 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
1556 GenerateUsageCounterIncrement(assembler, EBX); 1653 GenerateUsageCounterIncrement(assembler, EBX);
1557 GenerateNArgsCheckInlineCacheStub( 1654 GenerateNArgsCheckInlineCacheStub(
1558 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry); 1655 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
1559 } 1656 }
1560 1657
1561 1658
1562 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { 1659 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
1563 GenerateUsageCounterIncrement(assembler, EBX); 1660 GenerateUsageCounterIncrement(assembler, EBX);
1564 GenerateNArgsCheckInlineCacheStub( 1661 GenerateNArgsCheckInlineCacheStub(assembler, 2,
1565 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); 1662 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
1566 } 1663 }
1567 1664
1568 1665
1569 // Stub for compiling a function and jumping to the compiled code. 1666 // Stub for compiling a function and jumping to the compiled code.
1570 // ECX: IC-Data (for methods). 1667 // ECX: IC-Data (for methods).
1571 // EDX: Arguments descriptor. 1668 // EDX: Arguments descriptor.
1572 // EAX: Function. 1669 // EAX: Function.
1573 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { 1670 void StubCode::GenerateLazyCompileStub(Assembler* assembler) {
1574 __ EnterStubFrame(); 1671 __ EnterStubFrame();
1575 __ pushl(EDX); // Preserve arguments descriptor array. 1672 __ pushl(EDX); // Preserve arguments descriptor array.
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after
1941 const Register temp = ECX; 2038 const Register temp = ECX;
1942 __ movl(left, Address(ESP, 2 * kWordSize)); 2039 __ movl(left, Address(ESP, 2 * kWordSize));
1943 __ movl(right, Address(ESP, 1 * kWordSize)); 2040 __ movl(right, Address(ESP, 1 * kWordSize));
1944 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); 2041 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp);
1945 __ ret(); 2042 __ ret();
1946 } 2043 }
1947 2044
1948 } // namespace dart 2045 } // namespace dart
1949 2046
1950 #endif // defined TARGET_ARCH_IA32 2047 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698