| 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 1202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 Register ic_reg = R5; | 1213 Register ic_reg = R5; |
| 1214 Register func_reg = temp_reg; | 1214 Register func_reg = temp_reg; |
| 1215 ASSERT(temp_reg == R6); | 1215 ASSERT(temp_reg == R6); |
| 1216 __ ldr(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); | 1216 __ ldr(func_reg, FieldAddress(ic_reg, ICData::owner_offset())); |
| 1217 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1217 __ ldr(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1218 __ add(R7, R7, Operand(1)); | 1218 __ add(R7, R7, Operand(1)); |
| 1219 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); | 1219 __ str(R7, FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1220 } | 1220 } |
| 1221 | 1221 |
| 1222 | 1222 |
| 1223 // Note: R5 must be preserved. |
| 1224 // Attempt a quick Smi operation for known operations ('kind'). The ICData |
| 1225 // must have been primed with a Smi/Smi check that will be used for counting |
| 1226 // the invocations. |
| 1227 static void EmitFastSmiOp(Assembler* assembler, |
| 1228 Token::Kind kind, |
| 1229 intptr_t num_args, |
| 1230 Label* not_smi_or_overflow) { |
| 1231 __ ldr(R0, Address(SP, 0 * kWordSize)); |
| 1232 __ ldr(R1, Address(SP, 1 * kWordSize)); |
| 1233 __ orr(TMP, R0, Operand(R1)); |
| 1234 __ tst(TMP, Operand(kSmiTagMask)); |
| 1235 __ b(not_smi_or_overflow, NE); |
| 1236 switch (kind) { |
| 1237 case Token::kADD: { |
| 1238 __ adds(R0, R1, Operand(R0)); // Adds. |
| 1239 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1240 break; |
| 1241 } |
| 1242 case Token::kSUB: { |
| 1243 __ subs(R0, R1, Operand(R0)); // Subtract. |
| 1244 __ b(not_smi_or_overflow, VS); // Branch if overflow. |
| 1245 break; |
| 1246 } |
| 1247 case Token::kEQ: { |
| 1248 __ cmp(R0, Operand(R1)); |
| 1249 __ LoadObject(R0, Bool::True(), EQ); |
| 1250 __ LoadObject(R0, Bool::False(), NE); |
| 1251 break; |
| 1252 } |
| 1253 default: UNIMPLEMENTED(); |
| 1254 } |
| 1255 // R5: IC data object (preserved). |
| 1256 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); |
| 1257 // R6: ic_data_array with check entries: classes and target functions. |
| 1258 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); |
| 1259 // R6: points directly to the first ic data array element. |
| 1260 #if defined(DEBUG) |
| 1261 // Check that first entry is for Smi/Smi. |
| 1262 Label error, ok; |
| 1263 const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid)); |
| 1264 __ ldr(R1, Address(R6, 0)); |
| 1265 __ CompareImmediate(R1, imm_smi_cid); |
| 1266 __ b(&error, NE); |
| 1267 __ ldr(R1, Address(R6, kWordSize)); |
| 1268 __ CompareImmediate(R1, imm_smi_cid); |
| 1269 __ b(&ok, EQ); |
| 1270 __ Bind(&error); |
| 1271 __ Stop("Incorrect IC data"); |
| 1272 __ Bind(&ok); |
| 1273 #endif |
| 1274 // Update counter. |
| 1275 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; |
| 1276 __ LoadFromOffset(kWord, R1, R6, count_offset); |
| 1277 __ adds(R1, R1, Operand(Smi::RawValue(1))); |
| 1278 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. |
| 1279 __ StoreToOffset(kWord, R1, R6, count_offset); |
| 1280 __ Ret(); |
| 1281 } |
| 1282 |
| 1283 |
| 1223 // Generate inline cache check for 'num_args'. | 1284 // Generate inline cache check for 'num_args'. |
| 1224 // LR: return address. | 1285 // LR: return address. |
| 1225 // R5: inline cache data object. | 1286 // R5: inline cache data object. |
| 1226 // Control flow: | 1287 // Control flow: |
| 1227 // - If receiver is null -> jump to IC miss. | 1288 // - If receiver is null -> jump to IC miss. |
| 1228 // - If receiver is Smi -> load Smi class. | 1289 // - If receiver is Smi -> load Smi class. |
| 1229 // - If receiver is not-Smi -> load receiver's class. | 1290 // - If receiver is not-Smi -> load receiver's class. |
| 1230 // - Check if 'num_args' (including receiver) match any IC data group. | 1291 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1231 // - Match found -> jump to target. | 1292 // - Match found -> jump to target. |
| 1232 // - Match not found -> jump to IC miss. | 1293 // - Match not found -> jump to IC miss. |
| 1233 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1294 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1234 Assembler* assembler, | 1295 Assembler* assembler, |
| 1235 intptr_t num_args, | 1296 intptr_t num_args, |
| 1236 const RuntimeEntry& handle_ic_miss) { | 1297 const RuntimeEntry& handle_ic_miss, |
| 1298 Token::Kind kind) { |
| 1237 ASSERT(num_args > 0); | 1299 ASSERT(num_args > 0); |
| 1238 #if defined(DEBUG) | 1300 #if defined(DEBUG) |
| 1239 { Label ok; | 1301 { Label ok; |
| 1240 // Check that the IC data array has NumArgsTested() == num_args. | 1302 // Check that the IC data array has NumArgsTested() == num_args. |
| 1241 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1303 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1242 __ ldr(R6, FieldAddress(R5, ICData::state_bits_offset())); | 1304 __ ldr(R6, FieldAddress(R5, ICData::state_bits_offset())); |
| 1243 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1305 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1244 __ and_(R6, R6, Operand(ICData::NumArgsTestedMask())); | 1306 __ and_(R6, R6, Operand(ICData::NumArgsTestedMask())); |
| 1245 __ CompareImmediate(R6, num_args); | 1307 __ CompareImmediate(R6, num_args); |
| 1246 __ b(&ok, EQ); | 1308 __ b(&ok, EQ); |
| 1247 __ Stop("Incorrect stub for IC data"); | 1309 __ Stop("Incorrect stub for IC data"); |
| 1248 __ Bind(&ok); | 1310 __ Bind(&ok); |
| 1249 } | 1311 } |
| 1250 #endif // DEBUG | 1312 #endif // DEBUG |
| 1251 | 1313 |
| 1252 Label stepping, done_stepping; | 1314 Label stepping, done_stepping; |
| 1253 | 1315 |
| 1254 // Check single stepping. | 1316 // Check single stepping. |
| 1255 __ ldr(R6, FieldAddress(CTX, Context::isolate_offset())); | 1317 __ ldr(R6, FieldAddress(CTX, Context::isolate_offset())); |
| 1256 __ ldrb(R6, Address(R6, Isolate::single_step_offset())); | 1318 __ ldrb(R6, Address(R6, Isolate::single_step_offset())); |
| 1257 __ CompareImmediate(R6, 0); | 1319 __ CompareImmediate(R6, 0); |
| 1258 __ b(&stepping, NE); | 1320 __ b(&stepping, NE); |
| 1259 __ Bind(&done_stepping); | 1321 __ Bind(&done_stepping); |
| 1260 | 1322 |
| 1323 if (kind != Token::kILLEGAL) { |
| 1324 Label not_smi_or_overflow; |
| 1325 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1326 __ Bind(¬_smi_or_overflow); |
| 1327 } |
| 1328 |
| 1261 // Load arguments descriptor into R4. | 1329 // Load arguments descriptor into R4. |
| 1262 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); | 1330 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); |
| 1263 // Loop that checks if there is an IC data match. | 1331 // Loop that checks if there is an IC data match. |
| 1264 Label loop, update, test, found; | 1332 Label loop, update, test, found; |
| 1265 // R5: IC data object (preserved). | 1333 // R5: IC data object (preserved). |
| 1266 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); | 1334 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); |
| 1267 // R6: ic_data_array with check entries: classes and target functions. | 1335 // R6: ic_data_array with check entries: classes and target functions. |
| 1268 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); | 1336 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); |
| 1269 // R6: points directly to the first ic data array element. | 1337 // R6: points directly to the first ic data array element. |
| 1270 | 1338 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1375 // LR: return address. | 1443 // LR: return address. |
| 1376 // R5: inline cache data object. | 1444 // R5: inline cache data object. |
| 1377 // Inline cache data object structure: | 1445 // Inline cache data object structure: |
| 1378 // 0: function-name | 1446 // 0: function-name |
| 1379 // 1: N, number of arguments checked. | 1447 // 1: N, number of arguments checked. |
| 1380 // 2 .. (length - 1): group of checks, each check containing: | 1448 // 2 .. (length - 1): group of checks, each check containing: |
| 1381 // - N classes. | 1449 // - N classes. |
| 1382 // - 1 target function. | 1450 // - 1 target function. |
| 1383 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1451 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1384 GenerateUsageCounterIncrement(assembler, R6); | 1452 GenerateUsageCounterIncrement(assembler, R6); |
| 1385 GenerateNArgsCheckInlineCacheStub( | 1453 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1386 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1454 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1387 } | 1455 } |
| 1388 | 1456 |
| 1389 | 1457 |
| 1390 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1458 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1391 GenerateUsageCounterIncrement(assembler, R6); | 1459 GenerateUsageCounterIncrement(assembler, R6); |
| 1392 GenerateNArgsCheckInlineCacheStub( | 1460 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1393 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1461 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1394 } | 1462 } |
| 1395 | 1463 |
| 1396 | 1464 |
| 1397 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1465 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1398 GenerateUsageCounterIncrement(assembler, R6); | 1466 GenerateUsageCounterIncrement(assembler, R6); |
| 1399 GenerateNArgsCheckInlineCacheStub( | 1467 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1400 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1468 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1469 } |
| 1470 |
| 1471 |
| 1472 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { |
| 1473 GenerateUsageCounterIncrement(assembler, R6); |
| 1474 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1475 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); |
| 1476 } |
| 1477 |
| 1478 |
| 1479 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { |
| 1480 GenerateUsageCounterIncrement(assembler, R6); |
| 1481 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1482 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); |
| 1483 } |
| 1484 |
| 1485 |
| 1486 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { |
| 1487 GenerateUsageCounterIncrement(assembler, R6); |
| 1488 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1489 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); |
| 1401 } | 1490 } |
| 1402 | 1491 |
| 1403 | 1492 |
| 1404 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1493 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1405 Assembler* assembler) { | 1494 Assembler* assembler) { |
| 1406 GenerateOptimizedUsageCounterIncrement(assembler); | 1495 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1407 GenerateNArgsCheckInlineCacheStub( | 1496 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1408 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1497 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1409 } | 1498 } |
| 1410 | 1499 |
| 1411 | 1500 |
| 1412 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1501 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1413 Assembler* assembler) { | 1502 Assembler* assembler) { |
| 1414 GenerateOptimizedUsageCounterIncrement(assembler); | 1503 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1415 GenerateNArgsCheckInlineCacheStub( | 1504 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1416 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1505 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1417 } | 1506 } |
| 1418 | 1507 |
| 1419 | 1508 |
| 1420 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1509 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1421 Assembler* assembler) { | 1510 Assembler* assembler) { |
| 1422 GenerateOptimizedUsageCounterIncrement(assembler); | 1511 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1423 GenerateNArgsCheckInlineCacheStub( | 1512 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1424 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1513 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1425 } | 1514 } |
| 1426 | 1515 |
| 1427 | 1516 |
| 1428 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1517 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1429 GenerateNArgsCheckInlineCacheStub( | 1518 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1430 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1519 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1431 } | 1520 } |
| 1432 | 1521 |
| 1433 | 1522 |
| 1434 // Intermediary stub between a static call and its target. ICData contains | 1523 // Intermediary stub between a static call and its target. ICData contains |
| 1435 // the target function and the call count. | 1524 // the target function and the call count. |
| 1436 // R5: ICData | 1525 // R5: ICData |
| 1437 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1526 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1438 GenerateUsageCounterIncrement(assembler, R6); | 1527 GenerateUsageCounterIncrement(assembler, R6); |
| 1439 #if defined(DEBUG) | 1528 #if defined(DEBUG) |
| 1440 { Label ok; | 1529 { Label ok; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1490 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1579 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1491 __ Pop(R5); | 1580 __ Pop(R5); |
| 1492 __ LeaveStubFrame(); | 1581 __ LeaveStubFrame(); |
| 1493 __ b(&done_stepping); | 1582 __ b(&done_stepping); |
| 1494 } | 1583 } |
| 1495 | 1584 |
| 1496 | 1585 |
| 1497 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1586 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1498 GenerateUsageCounterIncrement(assembler, R6); | 1587 GenerateUsageCounterIncrement(assembler, R6); |
| 1499 GenerateNArgsCheckInlineCacheStub( | 1588 GenerateNArgsCheckInlineCacheStub( |
| 1500 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry); | 1589 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1501 } | 1590 } |
| 1502 | 1591 |
| 1503 | 1592 |
| 1504 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1593 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1505 GenerateUsageCounterIncrement(assembler, R6); | 1594 GenerateUsageCounterIncrement(assembler, R6); |
| 1506 GenerateNArgsCheckInlineCacheStub( | 1595 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1507 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); | 1596 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1508 } | 1597 } |
| 1509 | 1598 |
| 1510 | 1599 |
| 1511 // Stub for compiling a function and jumping to the compiled code. | 1600 // Stub for compiling a function and jumping to the compiled code. |
| 1512 // R5: IC-Data (for methods). | 1601 // R5: IC-Data (for methods). |
| 1513 // R4: Arguments descriptor. | 1602 // R4: Arguments descriptor. |
| 1514 // R0: Function. | 1603 // R0: Function. |
| 1515 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1604 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1516 // Preserve arg desc. and IC data object. | 1605 // Preserve arg desc. and IC data object. |
| 1517 __ EnterStubFrame(); | 1606 __ EnterStubFrame(); |
| (...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1867 const Register right = R0; | 1956 const Register right = R0; |
| 1868 __ ldr(left, Address(SP, 1 * kWordSize)); | 1957 __ ldr(left, Address(SP, 1 * kWordSize)); |
| 1869 __ ldr(right, Address(SP, 0 * kWordSize)); | 1958 __ ldr(right, Address(SP, 0 * kWordSize)); |
| 1870 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 1959 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1871 __ Ret(); | 1960 __ Ret(); |
| 1872 } | 1961 } |
| 1873 | 1962 |
| 1874 } // namespace dart | 1963 } // namespace dart |
| 1875 | 1964 |
| 1876 #endif // defined TARGET_ARCH_ARM | 1965 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |