Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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, ¬_smi_or_overflow); | 1362 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1367 } | 1363 } |
| 1368 __ Bind(¬_smi_or_overflow); | 1364 __ Bind(¬_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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |