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

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

Issue 2647913002: Optimizations to IC stub for unoptimized code performance on x64. (Closed)
Patch Set: Feedback from Regis Created 3 years, 10 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
« no previous file with comments | « runtime/vm/stub_code_mips.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 1290 matching lines...) Expand 10 before | Expand all | Expand 10 after
1301 __ j(NOT_EQUAL, &error, Assembler::kNearJump); 1301 __ j(NOT_EQUAL, &error, Assembler::kNearJump);
1302 __ cmpq(Address(R13, 1 * kWordSize), imm_smi_cid); 1302 __ cmpq(Address(R13, 1 * kWordSize), imm_smi_cid);
1303 __ j(EQUAL, &ok, Assembler::kNearJump); 1303 __ j(EQUAL, &ok, Assembler::kNearJump);
1304 __ Bind(&error); 1304 __ Bind(&error);
1305 __ Stop("Incorrect IC data"); 1305 __ Stop("Incorrect IC data");
1306 __ Bind(&ok); 1306 __ Bind(&ok);
1307 #endif 1307 #endif
1308 1308
1309 if (FLAG_optimization_counter_threshold >= 0) { 1309 if (FLAG_optimization_counter_threshold >= 0) {
1310 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; 1310 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1311 // Update counter. 1311 // Update counter, ignore overflow.
1312 __ movq(R8, Address(R13, count_offset)); 1312 __ addq(Address(R13, count_offset), Immediate(Smi::RawValue(1)));
1313 __ addq(R8, Immediate(Smi::RawValue(1)));
1314 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1315 __ cmovnoq(R9, R8);
1316 __ StoreIntoSmiField(Address(R13, count_offset), R9);
1317 } 1313 }
1318 1314
1319 __ ret(); 1315 __ ret();
1320 } 1316 }
1321 1317
1322 1318
1323 // Generate inline cache check for 'num_args'. 1319 // Generate inline cache check for 'num_args'.
1324 // RBX: Inline cache data object. 1320 // RBX: Inline cache data object.
1325 // TOS(0): return address 1321 // TOS(0): return address
1326 // Control flow: 1322 // Control flow:
1327 // - If receiver is null -> jump to IC miss. 1323 // - If receiver is null -> jump to IC miss.
1328 // - If receiver is Smi -> load Smi class. 1324 // - If receiver is Smi -> load Smi class.
1329 // - If receiver is not-Smi -> load receiver's class. 1325 // - If receiver is not-Smi -> load receiver's class.
1330 // - Check if 'num_args' (including receiver) match any IC data group. 1326 // - Check if 'num_args' (including receiver) match any IC data group.
1331 // - Match found -> jump to target. 1327 // - Match found -> jump to target.
1332 // - Match not found -> jump to IC miss. 1328 // - Match not found -> jump to IC miss.
1333 void StubCode::GenerateNArgsCheckInlineCacheStub( 1329 void StubCode::GenerateNArgsCheckInlineCacheStub(
1334 Assembler* assembler, 1330 Assembler* assembler,
1335 intptr_t num_args, 1331 intptr_t num_args,
1336 const RuntimeEntry& handle_ic_miss, 1332 const RuntimeEntry& handle_ic_miss,
1337 Token::Kind kind, 1333 Token::Kind kind,
1338 bool optimized) { 1334 bool optimized) {
1339 ASSERT(num_args > 0); 1335 ASSERT(num_args == 1 || num_args == 2);
1340 #if defined(DEBUG) 1336 #if defined(DEBUG)
1341 { 1337 {
1342 Label ok; 1338 Label ok;
1343 // Check that the IC data array has NumArgsTested() == num_args. 1339 // Check that the IC data array has NumArgsTested() == num_args.
1344 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. 1340 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'.
1345 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset())); 1341 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset()));
1346 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. 1342 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed.
1347 __ andq(RCX, Immediate(ICData::NumArgsTestedMask())); 1343 __ andq(RCX, Immediate(ICData::NumArgsTestedMask()));
1348 __ cmpq(RCX, Immediate(num_args)); 1344 __ cmpq(RCX, Immediate(num_args));
1349 __ j(EQUAL, &ok, Assembler::kNearJump); 1345 __ j(EQUAL, &ok, Assembler::kNearJump);
(...skipping 14 matching lines...) Expand all
1364 Label not_smi_or_overflow; 1360 Label not_smi_or_overflow;
1365 if (kind != Token::kILLEGAL) { 1361 if (kind != Token::kILLEGAL) {
1366 EmitFastSmiOp(assembler, kind, num_args, &not_smi_or_overflow); 1362 EmitFastSmiOp(assembler, kind, num_args, &not_smi_or_overflow);
1367 } 1363 }
1368 __ Bind(&not_smi_or_overflow); 1364 __ Bind(&not_smi_or_overflow);
1369 1365
1370 __ Comment("Extract ICData initial values and receiver cid"); 1366 __ Comment("Extract ICData initial values and receiver cid");
1371 // Load arguments descriptor into R10. 1367 // Load arguments descriptor into R10.
1372 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); 1368 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
1373 // Loop that checks if there is an IC data match. 1369 // Loop that checks if there is an IC data match.
1374 Label loop, update, test, found; 1370 Label loop, found, miss;
1375 // RBX: IC data object (preserved). 1371 // RBX: IC data object (preserved).
1376 __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset())); 1372 __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
1377 // R13: ic_data_array with check entries: classes and target functions. 1373 // R13: ic_data_array with check entries: classes and target functions.
1378 __ leaq(R13, FieldAddress(R13, Array::data_offset())); 1374 __ leaq(R13, FieldAddress(R13, Array::data_offset()));
1379 // R13: points directly to the first ic data array element. 1375 // R13: points directly to the first ic data array element.
1380 1376
1381 // Get the receiver's class ID (first read number of arguments from 1377 // Get argument descriptor into RCX.
1382 // arguments descriptor array and then access the receiver from the stack). 1378 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
1383 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); 1379 // Load first argument into R9.
1384 __ movq(R9, Address(RSP, RAX, TIMES_4, 0)); // RAX (argument count) is Smi. 1380 __ movq(R9, Address(RSP, RCX, TIMES_4, 0));
1385 __ LoadTaggedClassIdMayBeSmi(RAX, R9); 1381 __ LoadTaggedClassIdMayBeSmi(RAX, R9);
1386 // RAX: receiver's class ID as smi. 1382 // RAX: first argument class ID as Smi.
1387 __ movq(R9, Address(R13, 0)); // First class ID (Smi) to check. 1383 if (num_args == 2) {
1388 __ jmp(&test); 1384 // Load second argument into R9.
1385 __ movq(R9, Address(RSP, RCX, TIMES_4, -kWordSize));
1386 __ LoadTaggedClassIdMayBeSmi(RCX, R9);
1387 // RCX: second argument class ID (smi).
1388 }
1389 1389
1390 __ Comment("ICData loop"); 1390 __ Comment("ICData loop");
1391
1392 // We unroll the generic one that is generated once more than the others.
1393 bool optimize = kind == Token::kILLEGAL;
1394 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
1395 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1396
1391 __ Bind(&loop); 1397 __ Bind(&loop);
1392 for (int i = 0; i < num_args; i++) { 1398 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
1393 if (i > 0) { 1399 Label update;
1394 // If not the first, load the next argument's class ID. 1400 __ movq(R9, Address(R13, 0));
1395 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); 1401 __ cmpq(RAX, R9); // Class id match?
1396 __ movq(R9, Address(RSP, RAX, TIMES_4, -i * kWordSize)); 1402 if (num_args == 2) {
1397 __ LoadTaggedClassIdMayBeSmi(RAX, R9); 1403 __ j(NOT_EQUAL, &update); // Continue.
1398 // RAX: next argument class ID (smi). 1404 __ movq(R9, Address(R13, kWordSize));
1399 __ movq(R9, Address(R13, i * kWordSize));
1400 // R9: next class ID to check (smi). 1405 // R9: next class ID to check (smi).
1406 __ cmpq(RCX, R9); // Class id match?
1401 } 1407 }
1402 __ cmpq(RAX, R9); // Class id match? 1408 __ j(EQUAL, &found); // Break.
1403 if (i < (num_args - 1)) { 1409
1404 __ j(NOT_EQUAL, &update); // Continue. 1410 __ Bind(&update);
1411
1412 const intptr_t entry_size =
1413 ICData::TestEntryLengthFor(num_args) * kWordSize;
1414 __ addq(R13, Immediate(entry_size)); // Next entry.
1415
1416 __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid))); // Done?
1417 if (unroll == 0) {
1418 __ j(NOT_EQUAL, &loop);
1405 } else { 1419 } else {
1406 // Last check, all checks before matched. 1420 __ j(EQUAL, &miss);
1407 __ j(EQUAL, &found); // Break.
1408 } 1421 }
1409 } 1422 }
1410 __ Bind(&update);
1411 // Reload receiver class ID. It has not been destroyed when num_args == 1.
1412 if (num_args > 1) {
1413 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
1414 __ movq(R9, Address(RSP, RAX, TIMES_4, 0));
1415 __ LoadTaggedClassIdMayBeSmi(RAX, R9);
1416 }
1417 1423
1418 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; 1424 __ Bind(&miss);
1419 __ addq(R13, Immediate(entry_size)); // Next entry.
1420 __ movq(R9, Address(R13, 0)); // Next class ID.
1421
1422 __ Bind(&test);
1423 __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid))); // Done?
1424 __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
1425
1426 __ Comment("IC miss"); 1425 __ Comment("IC miss");
1427 // Compute address of arguments (first read number of arguments from 1426 // Compute address of arguments (first read number of arguments from
1428 // arguments descriptor array and then compute address on the stack). 1427 // arguments descriptor array and then compute address on the stack).
1429 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); 1428 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
1430 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. 1429 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi.
1431 __ EnterStubFrame(); 1430 __ EnterStubFrame();
1432 __ pushq(R10); // Preserve arguments descriptor array. 1431 __ pushq(R10); // Preserve arguments descriptor array.
1433 __ pushq(RBX); // Preserve IC data object. 1432 __ pushq(RBX); // Preserve IC data object.
1434 __ pushq(Immediate(0)); // Result slot. 1433 __ pushq(Immediate(0)); // Result slot.
1435 // Push call arguments. 1434 // Push call arguments.
(...skipping 14 matching lines...) Expand all
1450 __ LeaveStubFrame(); 1449 __ LeaveStubFrame();
1451 Label call_target_function; 1450 Label call_target_function;
1452 if (!FLAG_lazy_dispatchers) { 1451 if (!FLAG_lazy_dispatchers) {
1453 GenerateDispatcherCode(assembler, &call_target_function); 1452 GenerateDispatcherCode(assembler, &call_target_function);
1454 } else { 1453 } else {
1455 __ jmp(&call_target_function); 1454 __ jmp(&call_target_function);
1456 } 1455 }
1457 1456
1458 __ Bind(&found); 1457 __ Bind(&found);
1459 // R13: Pointer to an IC data check group. 1458 // R13: Pointer to an IC data check group.
1460 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
1461 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1462 __ movq(RAX, Address(R13, target_offset)); 1459 __ movq(RAX, Address(R13, target_offset));
1463 1460
1464 if (FLAG_optimization_counter_threshold >= 0) { 1461 if (FLAG_optimization_counter_threshold >= 0) {
1465 // Update counter.
1466 __ Comment("Update caller's counter"); 1462 __ Comment("Update caller's counter");
1467 __ movq(R8, Address(R13, count_offset)); 1463 // Ignore overflow.
1468 __ addq(R8, Immediate(Smi::RawValue(1))); 1464 __ addq(Address(R13, count_offset), Immediate(Smi::RawValue(1)));
1469 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1470 __ cmovnoq(R9, R8);
1471 __ StoreIntoSmiField(Address(R13, count_offset), R9);
1472 } 1465 }
1473 1466
1474 __ Comment("Call target"); 1467 __ Comment("Call target");
1475 __ Bind(&call_target_function); 1468 __ Bind(&call_target_function);
1476 // RAX: Target function. 1469 // RAX: Target function.
1477 Label is_compiled;
1478 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); 1470 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
1479 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset())); 1471 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
1480 __ jmp(RCX); 1472 __ jmp(RCX);
1481 1473
1482 if (FLAG_support_debugger && !optimized) { 1474 if (FLAG_support_debugger && !optimized) {
1483 __ Bind(&stepping); 1475 __ Bind(&stepping);
1484 __ EnterStubFrame(); 1476 __ EnterStubFrame();
1485 __ pushq(RBX); 1477 __ pushq(RBX);
1486 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); 1478 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0);
1487 __ popq(RBX); 1479 __ popq(RBX);
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
1604 1596
1605 // RBX: IC data object (preserved). 1597 // RBX: IC data object (preserved).
1606 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); 1598 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset()));
1607 // R12: ic_data_array with entries: target functions and count. 1599 // R12: ic_data_array with entries: target functions and count.
1608 __ leaq(R12, FieldAddress(R12, Array::data_offset())); 1600 __ leaq(R12, FieldAddress(R12, Array::data_offset()));
1609 // R12: points directly to the first ic data array element. 1601 // R12: points directly to the first ic data array element.
1610 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; 1602 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize;
1611 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; 1603 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
1612 1604
1613 if (FLAG_optimization_counter_threshold >= 0) { 1605 if (FLAG_optimization_counter_threshold >= 0) {
1614 // Increment count for this call. 1606 // Increment count for this call, ignore overflow.
1615 __ movq(R8, Address(R12, count_offset)); 1607 __ addq(Address(R12, count_offset), Immediate(Smi::RawValue(1)));
1616 __ addq(R8, Immediate(Smi::RawValue(1)));
1617 __ movq(R13, Immediate(Smi::RawValue(Smi::kMaxValue)));
1618 __ cmovnoq(R13, R8);
1619 __ StoreIntoSmiField(Address(R12, count_offset), R13);
1620 } 1608 }
1621 1609
1622 // Load arguments descriptor into R10. 1610 // Load arguments descriptor into R10.
1623 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); 1611 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
1624 1612
1625 // Get function and call it, if possible. 1613 // Get function and call it, if possible.
1626 __ movq(RAX, Address(R12, target_offset)); 1614 __ movq(RAX, Address(R12, target_offset));
1627 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); 1615 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
1628 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset())); 1616 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
1629 __ jmp(RCX); 1617 __ jmp(RCX);
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after
2276 } 2264 }
2277 2265
2278 2266
2279 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { 2267 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) {
2280 __ int3(); 2268 __ int3();
2281 } 2269 }
2282 2270
2283 } // namespace dart 2271 } // namespace dart
2284 2272
2285 #endif // defined TARGET_ARCH_X64 2273 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/stub_code_mips.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698