| 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_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 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/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 1321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1332 __ CompareImmediate(R1, imm_smi_cid); | 1332 __ CompareImmediate(R1, imm_smi_cid); |
| 1333 __ b(&error, NE); | 1333 __ b(&error, NE); |
| 1334 __ ldr(R1, Address(R8, kWordSize)); | 1334 __ ldr(R1, Address(R8, kWordSize)); |
| 1335 __ CompareImmediate(R1, imm_smi_cid); | 1335 __ CompareImmediate(R1, imm_smi_cid); |
| 1336 __ b(&ok, EQ); | 1336 __ b(&ok, EQ); |
| 1337 __ Bind(&error); | 1337 __ Bind(&error); |
| 1338 __ Stop("Incorrect IC data"); | 1338 __ Stop("Incorrect IC data"); |
| 1339 __ Bind(&ok); | 1339 __ Bind(&ok); |
| 1340 #endif | 1340 #endif |
| 1341 if (FLAG_optimization_counter_threshold >= 0) { | 1341 if (FLAG_optimization_counter_threshold >= 0) { |
| 1342 // Update counter, ignore overflow. | 1342 // Update counter. |
| 1343 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1343 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1344 __ LoadFromOffset(kWord, R1, R8, count_offset); | 1344 __ LoadFromOffset(kWord, R1, R8, count_offset); |
| 1345 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1345 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1346 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1346 __ StoreIntoSmiField(Address(R8, count_offset), R1); | 1347 __ StoreIntoSmiField(Address(R8, count_offset), R1); |
| 1347 } | 1348 } |
| 1348 __ Ret(); | 1349 __ Ret(); |
| 1349 } | 1350 } |
| 1350 | 1351 |
| 1351 | 1352 |
| 1352 // Generate inline cache check for 'num_args'. | 1353 // Generate inline cache check for 'num_args'. |
| 1353 // LR: return address. | 1354 // LR: return address. |
| 1354 // R9: inline cache data object. | 1355 // R9: inline cache data object. |
| 1355 // Control flow: | 1356 // Control flow: |
| 1356 // - If receiver is null -> jump to IC miss. | 1357 // - If receiver is null -> jump to IC miss. |
| 1357 // - If receiver is Smi -> load Smi class. | 1358 // - If receiver is Smi -> load Smi class. |
| 1358 // - If receiver is not-Smi -> load receiver's class. | 1359 // - If receiver is not-Smi -> load receiver's class. |
| 1359 // - Check if 'num_args' (including receiver) match any IC data group. | 1360 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1360 // - Match found -> jump to target. | 1361 // - Match found -> jump to target. |
| 1361 // - Match not found -> jump to IC miss. | 1362 // - Match not found -> jump to IC miss. |
| 1362 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1363 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1363 Assembler* assembler, | 1364 Assembler* assembler, |
| 1364 intptr_t num_args, | 1365 intptr_t num_args, |
| 1365 const RuntimeEntry& handle_ic_miss, | 1366 const RuntimeEntry& handle_ic_miss, |
| 1366 Token::Kind kind, | 1367 Token::Kind kind, |
| 1367 bool optimized) { | 1368 bool optimized) { |
| 1368 __ CheckCodePointer(); | 1369 __ CheckCodePointer(); |
| 1369 ASSERT(num_args == 1 || num_args == 2); | 1370 ASSERT(num_args > 0); |
| 1370 #if defined(DEBUG) | 1371 #if defined(DEBUG) |
| 1371 { | 1372 { |
| 1372 Label ok; | 1373 Label ok; |
| 1373 // Check that the IC data array has NumArgsTested() == num_args. | 1374 // Check that the IC data array has NumArgsTested() == num_args. |
| 1374 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1375 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1375 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); | 1376 __ ldr(R8, FieldAddress(R9, ICData::state_bits_offset())); |
| 1376 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1377 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1377 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); | 1378 __ and_(R8, R8, Operand(ICData::NumArgsTestedMask())); |
| 1378 __ CompareImmediate(R8, num_args); | 1379 __ CompareImmediate(R8, num_args); |
| 1379 __ b(&ok, EQ); | 1380 __ b(&ok, EQ); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1395 Label not_smi_or_overflow; | 1396 Label not_smi_or_overflow; |
| 1396 if (kind != Token::kILLEGAL) { | 1397 if (kind != Token::kILLEGAL) { |
| 1397 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | 1398 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1398 } | 1399 } |
| 1399 __ Bind(¬_smi_or_overflow); | 1400 __ Bind(¬_smi_or_overflow); |
| 1400 | 1401 |
| 1401 __ Comment("Extract ICData initial values and receiver cid"); | 1402 __ Comment("Extract ICData initial values and receiver cid"); |
| 1402 // Load arguments descriptor into R4. | 1403 // Load arguments descriptor into R4. |
| 1403 __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset())); | 1404 __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset())); |
| 1404 // Loop that checks if there is an IC data match. | 1405 // Loop that checks if there is an IC data match. |
| 1405 Label loop, found, miss; | 1406 Label loop, update, test, found; |
| 1406 // R9: IC data object (preserved). | 1407 // R9: IC data object (preserved). |
| 1407 __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset())); | 1408 __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset())); |
| 1408 // R8: ic_data_array with check entries: classes and target functions. | 1409 // R8: ic_data_array with check entries: classes and target functions. |
| 1409 const int kIcDataOffset = Array::data_offset() - kHeapObjectTag; | 1410 __ AddImmediate(R8, R8, Array::data_offset() - kHeapObjectTag); |
| 1410 // R8: points at the IC data array. | 1411 // R8: points directly to the first ic data array element. |
| 1411 | 1412 |
| 1412 // Get the receiver's class ID (first read number of arguments from | 1413 // Get the receiver's class ID (first read number of arguments from |
| 1413 // arguments descriptor array and then access the receiver from the stack). | 1414 // arguments descriptor array and then access the receiver from the stack). |
| 1414 __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset())); | 1415 __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset())); |
| 1415 __ sub(NOTFP, NOTFP, Operand(Smi::RawValue(1))); | 1416 __ sub(NOTFP, NOTFP, Operand(Smi::RawValue(1))); |
| 1417 __ ldr(R0, Address(SP, NOTFP, LSL, 1)); // NOTFP (argument_count - 1) is smi. |
| 1418 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1416 // NOTFP: argument_count - 1 (smi). | 1419 // NOTFP: argument_count - 1 (smi). |
| 1420 // R0: receiver's class ID (smi). |
| 1421 __ ldr(R1, Address(R8, 0)); // First class id (smi) to check. |
| 1422 __ b(&test); |
| 1417 | 1423 |
| 1418 __ Comment("ICData loop"); | 1424 __ Comment("ICData loop"); |
| 1419 | 1425 __ Bind(&loop); |
| 1420 __ ldr(R0, Address(SP, NOTFP, LSL, 1)); // NOTFP (argument_count - 1) is Smi. | 1426 for (int i = 0; i < num_args; i++) { |
| 1421 __ LoadTaggedClassIdMayBeSmi(R0, R0); | 1427 if (i > 0) { |
| 1422 if (num_args == 2) { | 1428 // If not the first, load the next argument's class ID. |
| 1423 __ sub(R1, NOTFP, Operand(Smi::RawValue(1))); | 1429 __ AddImmediate(R0, NOTFP, Smi::RawValue(-i)); |
| 1424 __ ldr(R1, Address(SP, R1, LSL, 1)); // R1 (argument_count - 2) is Smi. | 1430 __ ldr(R0, Address(SP, R0, LSL, 1)); |
| 1425 __ LoadTaggedClassIdMayBeSmi(R1, R1); | 1431 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1432 // R0: next argument class ID (smi). |
| 1433 __ LoadFromOffset(kWord, R1, R8, i * kWordSize); |
| 1434 // R1: next class ID to check (smi). |
| 1435 } |
| 1436 __ cmp(R0, Operand(R1)); // Class id match? |
| 1437 if (i < (num_args - 1)) { |
| 1438 __ b(&update, NE); // Continue. |
| 1439 } else { |
| 1440 // Last check, all checks before matched. |
| 1441 __ b(&found, EQ); // Break. |
| 1442 } |
| 1443 } |
| 1444 __ Bind(&update); |
| 1445 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 1446 if (num_args > 1) { |
| 1447 __ ldr(R0, Address(SP, NOTFP, LSL, 1)); |
| 1448 __ LoadTaggedClassIdMayBeSmi(R0, R0); |
| 1426 } | 1449 } |
| 1427 | 1450 |
| 1428 // We unroll the generic one that is generated once more than the others. | 1451 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 1429 bool optimize = kind == Token::kILLEGAL; | 1452 __ AddImmediate(R8, entry_size); // Next entry. |
| 1453 __ ldr(R1, Address(R8, 0)); // Next class ID. |
| 1430 | 1454 |
| 1431 __ Bind(&loop); | 1455 __ Bind(&test); |
| 1432 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) { | 1456 __ CompareImmediate(R1, Smi::RawValue(kIllegalCid)); // Done? |
| 1433 Label update; | 1457 __ b(&loop, NE); |
| 1434 | 1458 |
| 1435 __ ldr(R2, Address(R8, kIcDataOffset)); | |
| 1436 __ cmp(R0, Operand(R2)); // Class id match? | |
| 1437 if (num_args == 2) { | |
| 1438 __ b(&update, NE); // Continue. | |
| 1439 __ ldr(R2, Address(R8, kIcDataOffset + kWordSize)); | |
| 1440 __ cmp(R1, Operand(R2)); // Class id match? | |
| 1441 } | |
| 1442 __ b(&found, EQ); // Break. | |
| 1443 | |
| 1444 __ Bind(&update); | |
| 1445 | |
| 1446 const intptr_t entry_size = | |
| 1447 ICData::TestEntryLengthFor(num_args) * kWordSize; | |
| 1448 __ AddImmediate(R8, entry_size); // Next entry. | |
| 1449 | |
| 1450 __ CompareImmediate(R2, Smi::RawValue(kIllegalCid)); // Done? | |
| 1451 if (unroll == 0) { | |
| 1452 __ b(&loop, NE); | |
| 1453 } else { | |
| 1454 __ b(&miss, EQ); | |
| 1455 } | |
| 1456 } | |
| 1457 | |
| 1458 __ Bind(&miss); | |
| 1459 __ Comment("IC miss"); | 1459 __ Comment("IC miss"); |
| 1460 // Compute address of arguments. | 1460 // Compute address of arguments. |
| 1461 // NOTFP: argument_count - 1 (smi). | 1461 // NOTFP: argument_count - 1 (smi). |
| 1462 __ add(NOTFP, SP, Operand(NOTFP, LSL, 1)); // NOTFP is Smi. | 1462 __ add(NOTFP, SP, Operand(NOTFP, LSL, 1)); // NOTFP is Smi. |
| 1463 // NOTFP: address of receiver. | 1463 // NOTFP: address of receiver. |
| 1464 // Create a stub frame as we are pushing some objects on the stack before | 1464 // Create a stub frame as we are pushing some objects on the stack before |
| 1465 // calling into the runtime. | 1465 // calling into the runtime. |
| 1466 __ EnterStubFrame(); | 1466 __ EnterStubFrame(); |
| 1467 __ LoadImmediate(R0, 0); | 1467 __ LoadImmediate(R0, 0); |
| 1468 // Preserve IC data object and arguments descriptor array and | 1468 // Preserve IC data object and arguments descriptor array and |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1487 if (!FLAG_lazy_dispatchers) { | 1487 if (!FLAG_lazy_dispatchers) { |
| 1488 GenerateDispatcherCode(assembler, &call_target_function); | 1488 GenerateDispatcherCode(assembler, &call_target_function); |
| 1489 } else { | 1489 } else { |
| 1490 __ b(&call_target_function); | 1490 __ b(&call_target_function); |
| 1491 } | 1491 } |
| 1492 | 1492 |
| 1493 __ Bind(&found); | 1493 __ Bind(&found); |
| 1494 // R8: pointer to an IC data check group. | 1494 // R8: pointer to an IC data check group. |
| 1495 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; | 1495 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; |
| 1496 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | 1496 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1497 __ LoadFromOffset(kWord, R0, R8, kIcDataOffset + target_offset); | 1497 __ LoadFromOffset(kWord, R0, R8, target_offset); |
| 1498 | 1498 |
| 1499 if (FLAG_optimization_counter_threshold >= 0) { | 1499 if (FLAG_optimization_counter_threshold >= 0) { |
| 1500 __ Comment("Update caller's counter"); | 1500 __ Comment("Update caller's counter"); |
| 1501 __ LoadFromOffset(kWord, R1, R8, kIcDataOffset + count_offset); | 1501 __ LoadFromOffset(kWord, R1, R8, count_offset); |
| 1502 // Ignore overflow. | |
| 1503 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1502 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1504 __ StoreIntoSmiField(Address(R8, kIcDataOffset + count_offset), R1); | 1503 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1504 __ StoreIntoSmiField(Address(R8, count_offset), R1); |
| 1505 } | 1505 } |
| 1506 | 1506 |
| 1507 __ Comment("Call target"); | 1507 __ Comment("Call target"); |
| 1508 __ Bind(&call_target_function); | 1508 __ Bind(&call_target_function); |
| 1509 // R0: target function. | 1509 // R0: target function. |
| 1510 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 1510 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| 1511 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); | 1511 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1512 __ bx(R2); | 1512 __ bx(R2); |
| 1513 | 1513 |
| 1514 if (FLAG_support_debugger && !optimized) { | 1514 if (FLAG_support_debugger && !optimized) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1620 | 1620 |
| 1621 // R9: IC data object (preserved). | 1621 // R9: IC data object (preserved). |
| 1622 __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset())); | 1622 __ ldr(R8, FieldAddress(R9, ICData::ic_data_offset())); |
| 1623 // R8: ic_data_array with entries: target functions and count. | 1623 // R8: ic_data_array with entries: target functions and count. |
| 1624 __ AddImmediate(R8, R8, Array::data_offset() - kHeapObjectTag); | 1624 __ AddImmediate(R8, R8, Array::data_offset() - kHeapObjectTag); |
| 1625 // R8: points directly to the first ic data array element. | 1625 // R8: points directly to the first ic data array element. |
| 1626 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; | 1626 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; |
| 1627 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; | 1627 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; |
| 1628 | 1628 |
| 1629 if (FLAG_optimization_counter_threshold >= 0) { | 1629 if (FLAG_optimization_counter_threshold >= 0) { |
| 1630 // Increment count for this call, ignore overflow. | 1630 // Increment count for this call. |
| 1631 __ LoadFromOffset(kWord, R1, R8, count_offset); | 1631 __ LoadFromOffset(kWord, R1, R8, count_offset); |
| 1632 __ adds(R1, R1, Operand(Smi::RawValue(1))); | 1632 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1633 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1633 __ StoreIntoSmiField(Address(R8, count_offset), R1); | 1634 __ StoreIntoSmiField(Address(R8, count_offset), R1); |
| 1634 } | 1635 } |
| 1635 | 1636 |
| 1636 // Load arguments descriptor into R4. | 1637 // Load arguments descriptor into R4. |
| 1637 __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset())); | 1638 __ ldr(R4, FieldAddress(R9, ICData::arguments_descriptor_offset())); |
| 1638 | 1639 |
| 1639 // Get function and call it, if possible. | 1640 // Get function and call it, if possible. |
| 1640 __ LoadFromOffset(kWord, R0, R8, target_offset); | 1641 __ LoadFromOffset(kWord, R0, R8, target_offset); |
| 1641 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); | 1642 __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset())); |
| 1642 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); | 1643 __ ldr(R2, FieldAddress(R0, Function::entry_point_offset())); |
| (...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2280 } | 2281 } |
| 2281 | 2282 |
| 2282 | 2283 |
| 2283 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2284 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
| 2284 __ bkpt(0); | 2285 __ bkpt(0); |
| 2285 } | 2286 } |
| 2286 | 2287 |
| 2287 } // namespace dart | 2288 } // namespace dart |
| 2288 | 2289 |
| 2289 #endif // defined TARGET_ARCH_ARM | 2290 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |