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

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: Created 3 years, 11 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/assembler_x64.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 1291 matching lines...) Expand 10 before | Expand all | Expand 10 after
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.
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 __ Comment("ICData loop");
1382 // arguments descriptor array and then access the receiver from the stack).
1383 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
1384 __ movq(R9, Address(RSP, RAX, TIMES_4, 0)); // RAX (argument count) is Smi.
1385 __ LoadTaggedClassIdMayBeSmi(RAX, R9);
1386 // RAX: receiver's class ID as smi.
1387 __ movq(R9, Address(R13, 0)); // First class ID (Smi) to check.
1388 __ jmp(&test);
1389 1378
1390 __ Comment("ICData loop"); 1379 // We only unroll the generic one that is generated once.
1380 bool optimize = kind == Token::kILLEGAL;
1381 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
1382 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1383
1384 bool receiver_loaded = false;
1385
1391 __ Bind(&loop); 1386 __ Bind(&loop);
1392 for (int i = 0; i < num_args; i++) { 1387 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
1393 if (i > 0) { 1388 Label update;
1394 // If not the first, load the next argument's class ID. 1389 if (!receiver_loaded) {
1395 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); 1390 receiver_loaded = true;
1396 __ movq(R9, Address(RSP, RAX, TIMES_4, -i * kWordSize)); 1391 // Get argument descriptor into RCX.
1392 __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
1393 // Load first argument into R9.
1394 __ movq(R9, Address(RSP, RCX, TIMES_4, 0));
1397 __ LoadTaggedClassIdMayBeSmi(RAX, R9); 1395 __ LoadTaggedClassIdMayBeSmi(RAX, R9);
1398 // RAX: next argument class ID (smi). 1396 // RAX: first argument class ID (smi).
1397 if (num_args == 2) {
1398 // Load second argument into R9.
1399 __ movq(R9, Address(RSP, RCX, TIMES_4, -kWordSize));
1400 __ LoadTaggedClassIdMayBeSmi(RCX, R9);
1401 // RCX: second argument class ID (smi).
1402 }
1403 }
1404 for (int i = 0; i < num_args; i++) {
1399 __ movq(R9, Address(R13, i * kWordSize)); 1405 __ movq(R9, Address(R13, i * kWordSize));
1400 // R9: next class ID to check (smi). 1406 // R9: next class ID to check (smi).
1407 __ cmpq(i == 0 ? RAX : RCX, R9); // Class id match?
1408 if (i < (num_args - 1)) {
1409 __ j(NOT_EQUAL, &update); // Continue.
1410 } else {
1411 // Last check, all checks before matched.
1412 __ j(EQUAL, &found); // Break.
1413 }
1401 } 1414 }
1402 __ cmpq(RAX, R9); // Class id match? 1415 __ Bind(&update);
1403 if (i < (num_args - 1)) { 1416
1404 __ j(NOT_EQUAL, &update); // Continue. 1417 const intptr_t entry_size =
1418 ICData::TestEntryLengthFor(num_args) * kWordSize;
1419 __ addq(R13, Immediate(entry_size)); // Next entry.
1420
1421 __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid))); // Done?
1422 if (unroll == 0) {
1423 __ j(NOT_EQUAL, &loop);
1405 } else { 1424 } else {
1406 // Last check, all checks before matched. 1425 __ j(EQUAL, &miss);
1407 __ j(EQUAL, &found); // Break.
1408 } 1426 }
1409 } 1427 }
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 1428
1418 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; 1429 __ 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"); 1430 __ Comment("IC miss");
1427 // Compute address of arguments (first read number of arguments from 1431 // Compute address of arguments (first read number of arguments from
1428 // arguments descriptor array and then compute address on the stack). 1432 // arguments descriptor array and then compute address on the stack).
1429 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); 1433 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
1430 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. 1434 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi.
1431 __ EnterStubFrame(); 1435 __ EnterStubFrame();
1432 __ pushq(R10); // Preserve arguments descriptor array. 1436 __ pushq(R10); // Preserve arguments descriptor array.
1433 __ pushq(RBX); // Preserve IC data object. 1437 __ pushq(RBX); // Preserve IC data object.
1434 __ pushq(Immediate(0)); // Result slot. 1438 __ pushq(Immediate(0)); // Result slot.
1435 // Push call arguments. 1439 // Push call arguments.
(...skipping 14 matching lines...) Expand all
1450 __ LeaveStubFrame(); 1454 __ LeaveStubFrame();
1451 Label call_target_function; 1455 Label call_target_function;
1452 if (!FLAG_lazy_dispatchers) { 1456 if (!FLAG_lazy_dispatchers) {
1453 GenerateDispatcherCode(assembler, &call_target_function); 1457 GenerateDispatcherCode(assembler, &call_target_function);
1454 } else { 1458 } else {
1455 __ jmp(&call_target_function); 1459 __ jmp(&call_target_function);
1456 } 1460 }
1457 1461
1458 __ Bind(&found); 1462 __ Bind(&found);
1459 // R13: Pointer to an IC data check group. 1463 // 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)); 1464 __ movq(RAX, Address(R13, target_offset));
1463 1465
1464 if (FLAG_optimization_counter_threshold >= 0) { 1466 if (FLAG_optimization_counter_threshold >= 0) {
1465 // Update counter.
1466 __ Comment("Update caller's counter"); 1467 __ Comment("Update caller's counter");
1467 __ movq(R8, Address(R13, count_offset)); 1468 __ addq(Address(R13, count_offset), Immediate(Smi::RawValue(1)));
1468 __ addq(R8, Immediate(Smi::RawValue(1)));
1469 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1470 __ cmovnoq(R9, R8);
1471 __ StoreIntoSmiField(Address(R13, count_offset), R9);
1472 } 1469 }
1473 1470
1474 __ Comment("Call target"); 1471 __ Comment("Call target");
1475 __ Bind(&call_target_function); 1472 __ Bind(&call_target_function);
1476 // RAX: Target function. 1473 // RAX: Target function.
1477 Label is_compiled;
1478 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); 1474 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
1479 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset())); 1475 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
1480 __ jmp(RCX); 1476 __ jmp(RCX);
1481 1477
1482 if (FLAG_support_debugger && !optimized) { 1478 if (FLAG_support_debugger && !optimized) {
1483 __ Bind(&stepping); 1479 __ Bind(&stepping);
1484 __ EnterStubFrame(); 1480 __ EnterStubFrame();
1485 __ pushq(RBX); 1481 __ pushq(RBX);
1486 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); 1482 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0);
1487 __ popq(RBX); 1483 __ popq(RBX);
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
1605 // RBX: IC data object (preserved). 1601 // RBX: IC data object (preserved).
1606 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); 1602 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset()));
1607 // R12: ic_data_array with entries: target functions and count. 1603 // R12: ic_data_array with entries: target functions and count.
1608 __ leaq(R12, FieldAddress(R12, Array::data_offset())); 1604 __ leaq(R12, FieldAddress(R12, Array::data_offset()));
1609 // R12: points directly to the first ic data array element. 1605 // R12: points directly to the first ic data array element.
1610 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; 1606 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize;
1611 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; 1607 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
1612 1608
1613 if (FLAG_optimization_counter_threshold >= 0) { 1609 if (FLAG_optimization_counter_threshold >= 0) {
1614 // Increment count for this call. 1610 // Increment count for this call.
1615 __ movq(R8, Address(R12, count_offset)); 1611 __ addq(Address(R12, count_offset), Immediate(Smi::RawValue(1)));
Florian Schneider 2017/01/20 17:26:35 I think this should be safe: We already use INT_MI
erikcorry 2017/01/24 15:35:41 I'll make this change on 32 bit too, then. It is
regis 2017/01/24 18:27:21 Definitely a 64-bit overflow check. My bad. I got
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 } 1612 }
1621 1613
1622 // Load arguments descriptor into R10. 1614 // Load arguments descriptor into R10.
1623 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); 1615 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
1624 1616
1625 // Get function and call it, if possible. 1617 // Get function and call it, if possible.
1626 __ movq(RAX, Address(R12, target_offset)); 1618 __ movq(RAX, Address(R12, target_offset));
1627 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); 1619 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
1628 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset())); 1620 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
1629 __ jmp(RCX); 1621 __ jmp(RCX);
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after
2276 } 2268 }
2277 2269
2278 2270
2279 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { 2271 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) {
2280 __ int3(); 2272 __ int3();
2281 } 2273 }
2282 2274
2283 } // namespace dart 2275 } // namespace dart
2284 2276
2285 #endif // defined TARGET_ARCH_X64 2277 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/assembler_x64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698