| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 1362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 __ b(&error, NE); | 1373 __ b(&error, NE); |
| 1374 __ ldr(R1, Address(R6, kWordSize)); | 1374 __ ldr(R1, Address(R6, kWordSize)); |
| 1375 __ CompareImmediate(R1, imm_smi_cid); | 1375 __ CompareImmediate(R1, imm_smi_cid); |
| 1376 __ b(&ok, EQ); | 1376 __ b(&ok, EQ); |
| 1377 __ Bind(&error); | 1377 __ Bind(&error); |
| 1378 __ Stop("Incorrect IC data"); | 1378 __ Stop("Incorrect IC data"); |
| 1379 __ Bind(&ok); | 1379 __ Bind(&ok); |
| 1380 #endif | 1380 #endif |
| 1381 if (FLAG_optimization_counter_threshold >= 0) { | 1381 if (FLAG_optimization_counter_threshold >= 0) { |
| 1382 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1382 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1383 // Update counter, ignore overflow. | 1383 // Update counter. |
| 1384 __ LoadFromOffset(R1, R6, count_offset); | 1384 __ LoadFromOffset(R1, R6, count_offset); |
| 1385 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1385 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1386 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); |
| 1387 __ csel(R1, R2, R1, VS); // Overflow. |
| 1386 __ StoreToOffset(R1, R6, count_offset); | 1388 __ StoreToOffset(R1, R6, count_offset); |
| 1387 } | 1389 } |
| 1388 | 1390 |
| 1389 __ ret(); | 1391 __ ret(); |
| 1390 } | 1392 } |
| 1391 | 1393 |
| 1392 | 1394 |
| 1393 // Generate inline cache check for 'num_args'. | 1395 // Generate inline cache check for 'num_args'. |
| 1394 // LR: return address. | 1396 // LR: return address. |
| 1395 // R5: inline cache data object. | 1397 // R5: inline cache data object. |
| 1396 // Control flow: | 1398 // Control flow: |
| 1397 // - If receiver is null -> jump to IC miss. | 1399 // - If receiver is null -> jump to IC miss. |
| 1398 // - If receiver is Smi -> load Smi class. | 1400 // - If receiver is Smi -> load Smi class. |
| 1399 // - If receiver is not-Smi -> load receiver's class. | 1401 // - If receiver is not-Smi -> load receiver's class. |
| 1400 // - Check if 'num_args' (including receiver) match any IC data group. | 1402 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1401 // - Match found -> jump to target. | 1403 // - Match found -> jump to target. |
| 1402 // - Match not found -> jump to IC miss. | 1404 // - Match not found -> jump to IC miss. |
| 1403 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1405 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1404 Assembler* assembler, | 1406 Assembler* assembler, |
| 1405 intptr_t num_args, | 1407 intptr_t num_args, |
| 1406 const RuntimeEntry& handle_ic_miss, | 1408 const RuntimeEntry& handle_ic_miss, |
| 1407 Token::Kind kind, | 1409 Token::Kind kind, |
| 1408 bool optimized) { | 1410 bool optimized) { |
| 1409 ASSERT(num_args == 1 || num_args == 2); | 1411 ASSERT(num_args > 0); |
| 1410 #if defined(DEBUG) | 1412 #if defined(DEBUG) |
| 1411 { | 1413 { |
| 1412 Label ok; | 1414 Label ok; |
| 1413 // Check that the IC data array has NumArgsTested() == num_args. | 1415 // Check that the IC data array has NumArgsTested() == num_args. |
| 1414 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1416 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1415 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, | 1417 __ LoadFromOffset(R6, R5, ICData::state_bits_offset() - kHeapObjectTag, |
| 1416 kUnsignedWord); | 1418 kUnsignedWord); |
| 1417 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1419 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1418 __ andi(R6, R6, Immediate(ICData::NumArgsTestedMask())); | 1420 __ andi(R6, R6, Immediate(ICData::NumArgsTestedMask())); |
| 1419 __ CompareImmediate(R6, num_args); | 1421 __ CompareImmediate(R6, num_args); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1436 Label not_smi_or_overflow; | 1438 Label not_smi_or_overflow; |
| 1437 if (kind != Token::kILLEGAL) { | 1439 if (kind != Token::kILLEGAL) { |
| 1438 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | 1440 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1439 } | 1441 } |
| 1440 __ Bind(¬_smi_or_overflow); | 1442 __ Bind(¬_smi_or_overflow); |
| 1441 | 1443 |
| 1442 __ Comment("Extract ICData initial values and receiver cid"); | 1444 __ Comment("Extract ICData initial values and receiver cid"); |
| 1443 // Load arguments descriptor into R4. | 1445 // Load arguments descriptor into R4. |
| 1444 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); | 1446 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); |
| 1445 // Loop that checks if there is an IC data match. | 1447 // Loop that checks if there is an IC data match. |
| 1446 Label loop, found, miss; | 1448 Label loop, update, test, found; |
| 1447 // R5: IC data object (preserved). | 1449 // R5: IC data object (preserved). |
| 1448 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); | 1450 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); |
| 1449 // R6: ic_data_array with check entries: classes and target functions. | 1451 // R6: ic_data_array with check entries: classes and target functions. |
| 1450 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); | 1452 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); |
| 1451 // R6: points directly to the first ic data array element. | 1453 // R6: points directly to the first ic data array element. |
| 1452 | 1454 |
| 1453 // Get the receiver's class ID (first read number of arguments from | 1455 // Get the receiver's class ID (first read number of arguments from |
| 1454 // arguments descriptor array and then access the receiver from the stack). | 1456 // arguments descriptor array and then access the receiver from the stack). |
| 1455 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); | 1457 __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset()); |
| 1456 __ SmiUntag(R7); // Untag so we can use the LSL 3 addressing mode. | 1458 __ SmiUntag(R7); // Untag so we can use the LSL 3 addressing mode. |
| 1457 __ sub(R7, R7, Operand(1)); | 1459 __ sub(R7, R7, Operand(1)); |
| 1458 | 1460 |
| 1459 // R0 <- [SP + (R7 << 3)] | 1461 // R0 <- [SP + (R7 << 3)] |
| 1460 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); | 1462 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); |
| 1461 __ LoadTaggedClassIdMayBeSmi(R0, R0); | 1463 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1462 | 1464 |
| 1463 if (num_args == 2) { | 1465 // R7: argument_count - 1 (untagged). |
| 1464 __ AddImmediate(R1, R7, -1); | 1466 // R0: receiver's class ID (smi). |
| 1465 // R1 <- [SP + (R1 << 3)] | 1467 __ ldr(R1, Address(R6)); // First class id (smi) to check. |
| 1466 __ ldr(R1, Address(SP, R1, UXTX, Address::Scaled)); | 1468 __ b(&test); |
| 1467 __ LoadTaggedClassIdMayBeSmi(R1, R1); | |
| 1468 } | |
| 1469 | |
| 1470 // We unroll the generic one that is generated once more than the others. | |
| 1471 bool optimize = kind == Token::kILLEGAL; | |
| 1472 | 1469 |
| 1473 __ Comment("ICData loop"); | 1470 __ Comment("ICData loop"); |
| 1474 __ Bind(&loop); | 1471 __ Bind(&loop); |
| 1475 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) { | 1472 for (int i = 0; i < num_args; i++) { |
| 1476 Label update; | 1473 if (i > 0) { |
| 1477 | 1474 // If not the first, load the next argument's class ID. |
| 1478 __ LoadFromOffset(R2, R6, 0); | 1475 __ AddImmediate(R0, R7, -i); |
| 1479 __ CompareRegisters(R0, R2); // Class id match? | 1476 // R0 <- [SP + (R0 << 3)] |
| 1480 if (num_args == 2) { | 1477 __ ldr(R0, Address(SP, R0, UXTX, Address::Scaled)); |
| 1478 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1479 // R0: next argument class ID (smi). |
| 1480 __ LoadFromOffset(R1, R6, i * kWordSize); |
| 1481 // R1: next class ID to check (smi). |
| 1482 } |
| 1483 __ CompareRegisters(R0, R1); // Class id match? |
| 1484 if (i < (num_args - 1)) { |
| 1481 __ b(&update, NE); // Continue. | 1485 __ b(&update, NE); // Continue. |
| 1482 __ LoadFromOffset(R2, R6, kWordSize); | |
| 1483 __ CompareRegisters(R1, R2); // Class id match? | |
| 1484 } | |
| 1485 __ b(&found, EQ); // Break. | |
| 1486 | |
| 1487 __ Bind(&update); | |
| 1488 | |
| 1489 const intptr_t entry_size = | |
| 1490 ICData::TestEntryLengthFor(num_args) * kWordSize; | |
| 1491 __ AddImmediate(R6, R6, entry_size); // Next entry. | |
| 1492 | |
| 1493 __ CompareImmediate(R2, Smi::RawValue(kIllegalCid)); // Done? | |
| 1494 if (unroll == 0) { | |
| 1495 __ b(&loop, NE); | |
| 1496 } else { | 1486 } else { |
| 1497 __ b(&miss, EQ); | 1487 // Last check, all checks before matched. |
| 1488 __ b(&found, EQ); // Break. |
| 1498 } | 1489 } |
| 1499 } | 1490 } |
| 1491 __ Bind(&update); |
| 1492 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 1493 if (num_args > 1) { |
| 1494 __ ldr(R0, Address(SP, R7, UXTX, Address::Scaled)); |
| 1495 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1496 } |
| 1500 | 1497 |
| 1501 __ Bind(&miss); | 1498 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 1499 __ AddImmediate(R6, R6, entry_size); // Next entry. |
| 1500 __ ldr(R1, Address(R6)); // Next class ID. |
| 1501 |
| 1502 __ Bind(&test); |
| 1503 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done? |
| 1504 __ b(&loop, NE); |
| 1505 |
| 1502 __ Comment("IC miss"); | 1506 __ Comment("IC miss"); |
| 1503 // Compute address of arguments. | 1507 // Compute address of arguments. |
| 1504 // R7: argument_count - 1 (untagged). | 1508 // R7: argument_count - 1 (untagged). |
| 1505 // R7 <- SP + (R7 << 3) | 1509 // R7 <- SP + (R7 << 3) |
| 1506 __ add(R7, SP, Operand(R7, UXTX, 3)); // R7 is Untagged. | 1510 __ add(R7, SP, Operand(R7, UXTX, 3)); // R7 is Untagged. |
| 1507 // R7: address of receiver. | 1511 // R7: address of receiver. |
| 1508 // Create a stub frame as we are pushing some objects on the stack before | 1512 // Create a stub frame as we are pushing some objects on the stack before |
| 1509 // calling into the runtime. | 1513 // calling into the runtime. |
| 1510 __ EnterStubFrame(); | 1514 __ EnterStubFrame(); |
| 1511 // Preserve IC data object and arguments descriptor array and | 1515 // Preserve IC data object and arguments descriptor array and |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1539 } | 1543 } |
| 1540 | 1544 |
| 1541 __ Bind(&found); | 1545 __ Bind(&found); |
| 1542 __ Comment("Update caller's counter"); | 1546 __ Comment("Update caller's counter"); |
| 1543 // R6: pointer to an IC data check group. | 1547 // R6: pointer to an IC data check group. |
| 1544 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1548 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 1545 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1549 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1546 __ LoadFromOffset(R0, R6, target_offset); | 1550 __ LoadFromOffset(R0, R6, target_offset); |
| 1547 | 1551 |
| 1548 if (FLAG_optimization_counter_threshold >= 0) { | 1552 if (FLAG_optimization_counter_threshold >= 0) { |
| 1549 // Update counter, ignore overflow. | 1553 // Update counter. |
| 1550 __ LoadFromOffset(R1, R6, count_offset); | 1554 __ LoadFromOffset(R1, R6, count_offset); |
| 1551 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1555 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1556 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); |
| 1557 __ csel(R1, R2, R1, VS); // Overflow. |
| 1552 __ StoreToOffset(R1, R6, count_offset); | 1558 __ StoreToOffset(R1, R6, count_offset); |
| 1553 } | 1559 } |
| 1554 | 1560 |
| 1555 __ Comment("Call target"); | 1561 __ Comment("Call target"); |
| 1556 __ Bind(&call_target_function); | 1562 __ Bind(&call_target_function); |
| 1557 // R0: target function. | 1563 // R0: target function. |
| 1558 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | 1564 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
| 1559 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | 1565 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
| 1560 __ br(R2); | 1566 __ br(R2); |
| 1561 | 1567 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1666 | 1672 |
| 1667 // R5: IC data object (preserved). | 1673 // R5: IC data object (preserved). |
| 1668 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); | 1674 __ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset()); |
| 1669 // R6: ic_data_array with entries: target functions and count. | 1675 // R6: ic_data_array with entries: target functions and count. |
| 1670 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); | 1676 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); |
| 1671 // R6: points directly to the first ic data array element. | 1677 // R6: points directly to the first ic data array element. |
| 1672 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; | 1678 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; |
| 1673 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; | 1679 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; |
| 1674 | 1680 |
| 1675 if (FLAG_optimization_counter_threshold >= 0) { | 1681 if (FLAG_optimization_counter_threshold >= 0) { |
| 1676 // Increment count for this call, ignore overflow. | 1682 // Increment count for this call. |
| 1677 __ LoadFromOffset(R1, R6, count_offset); | 1683 __ LoadFromOffset(R1, R6, count_offset); |
| 1678 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1684 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1685 __ LoadImmediate(R2, Smi::RawValue(Smi::kMaxValue)); |
| 1686 __ csel(R1, R2, R1, VS); // Overflow. |
| 1679 __ StoreToOffset(R1, R6, count_offset); | 1687 __ StoreToOffset(R1, R6, count_offset); |
| 1680 } | 1688 } |
| 1681 | 1689 |
| 1682 // Load arguments descriptor into R4. | 1690 // Load arguments descriptor into R4. |
| 1683 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); | 1691 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); |
| 1684 | 1692 |
| 1685 // Get function and call it, if possible. | 1693 // Get function and call it, if possible. |
| 1686 __ LoadFromOffset(R0, R6, target_offset); | 1694 __ LoadFromOffset(R0, R6, target_offset); |
| 1687 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); | 1695 __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
| 1688 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); | 1696 __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
| (...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2329 } | 2337 } |
| 2330 | 2338 |
| 2331 | 2339 |
| 2332 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2340 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
| 2333 __ brk(0); | 2341 __ brk(0); |
| 2334 } | 2342 } |
| 2335 | 2343 |
| 2336 } // namespace dart | 2344 } // namespace dart |
| 2337 | 2345 |
| 2338 #endif // defined TARGET_ARCH_ARM64 | 2346 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |