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_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: { | |
|
zra
2014/08/15 21:45:08
Use conditional ops:
__ cmp(R0, Operand(R1));
__
srdjan
2014/08/18 20:40:27
Done.
| |
| 1248 Label done, is_true; | |
| 1249 __ cmp(R0, Operand(R1)); | |
| 1250 __ b(&is_true, EQ); | |
| 1251 __ LoadObject(R0, Bool::False()); | |
| 1252 __ b(&done); | |
| 1253 __ Bind(&is_true); | |
| 1254 __ LoadObject(R0, Bool::True()); | |
| 1255 __ Bind(&done); | |
| 1256 break; | |
| 1257 } | |
| 1258 default: UNIMPLEMENTED(); | |
| 1259 } | |
| 1260 // R5: IC data object (preserved). | |
| 1261 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); | |
| 1262 // R6: ic_data_array with check entries: classes and target functions. | |
| 1263 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); | |
| 1264 // R6: points directly to the first ic data array element. | |
| 1265 #ifdef DEBUG | |
| 1266 // Check that first entry is for Smi/Smi. | |
| 1267 Label error, ok; | |
| 1268 const intptr_t imm_smi_cid = reinterpret_cast<intptr_t>(Smi::New(kSmiCid)); | |
| 1269 __ ldr(R1, Address(R6, 0)); | |
| 1270 __ CompareImmediate(R1, imm_smi_cid); | |
| 1271 __ b(&error, NE); | |
| 1272 __ ldr(R1, Address(R6, kWordSize)); | |
| 1273 __ CompareImmediate(R1, imm_smi_cid); | |
| 1274 __ b(&ok, EQ); | |
| 1275 __ Bind(&error); | |
|
zra
2014/08/15 21:45:08
If it's impossible to recover after incorrect IC d
srdjan
2014/08/18 20:40:27
I would need to have two If defined(DEBUG), the pe
zra
2014/08/18 21:00:29
Ah, okay. Missed that this was debug-only.
| |
| 1276 __ Stop("Incorrect IC data"); | |
| 1277 __ Bind(&ok); | |
| 1278 #endif | |
| 1279 // Update counter. | |
| 1280 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; | |
| 1281 __ LoadFromOffset(kWord, R1, R6, count_offset); | |
| 1282 __ adds(R1, R1, Operand(Smi::RawValue(1))); | |
| 1283 __ LoadImmediate(R1, Smi::RawValue(Smi::kMaxValue), VS); // Overflow. | |
| 1284 __ StoreToOffset(kWord, R1, R6, count_offset); | |
| 1285 __ Ret(); | |
| 1286 } | |
| 1287 | |
| 1288 | |
| 1223 // Generate inline cache check for 'num_args'. | 1289 // Generate inline cache check for 'num_args'. |
| 1224 // LR: return address. | 1290 // LR: return address. |
| 1225 // R5: inline cache data object. | 1291 // R5: inline cache data object. |
| 1226 // Control flow: | 1292 // Control flow: |
| 1227 // - If receiver is null -> jump to IC miss. | 1293 // - If receiver is null -> jump to IC miss. |
| 1228 // - If receiver is Smi -> load Smi class. | 1294 // - If receiver is Smi -> load Smi class. |
| 1229 // - If receiver is not-Smi -> load receiver's class. | 1295 // - If receiver is not-Smi -> load receiver's class. |
| 1230 // - Check if 'num_args' (including receiver) match any IC data group. | 1296 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1231 // - Match found -> jump to target. | 1297 // - Match found -> jump to target. |
| 1232 // - Match not found -> jump to IC miss. | 1298 // - Match not found -> jump to IC miss. |
| 1233 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1299 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1234 Assembler* assembler, | 1300 Assembler* assembler, |
| 1235 intptr_t num_args, | 1301 intptr_t num_args, |
| 1236 const RuntimeEntry& handle_ic_miss) { | 1302 const RuntimeEntry& handle_ic_miss, |
| 1303 Token::Kind kind) { | |
| 1237 ASSERT(num_args > 0); | 1304 ASSERT(num_args > 0); |
| 1238 #if defined(DEBUG) | 1305 #if defined(DEBUG) |
| 1239 { Label ok; | 1306 { Label ok; |
| 1240 // Check that the IC data array has NumArgsTested() == num_args. | 1307 // Check that the IC data array has NumArgsTested() == num_args. |
| 1241 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1308 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1242 __ ldr(R6, FieldAddress(R5, ICData::state_bits_offset())); | 1309 __ ldr(R6, FieldAddress(R5, ICData::state_bits_offset())); |
| 1243 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1310 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1244 __ and_(R6, R6, Operand(ICData::NumArgsTestedMask())); | 1311 __ and_(R6, R6, Operand(ICData::NumArgsTestedMask())); |
| 1245 __ CompareImmediate(R6, num_args); | 1312 __ CompareImmediate(R6, num_args); |
| 1246 __ b(&ok, EQ); | 1313 __ b(&ok, EQ); |
| 1247 __ Stop("Incorrect stub for IC data"); | 1314 __ Stop("Incorrect stub for IC data"); |
| 1248 __ Bind(&ok); | 1315 __ Bind(&ok); |
| 1249 } | 1316 } |
| 1250 #endif // DEBUG | 1317 #endif // DEBUG |
| 1251 | 1318 |
| 1252 Label stepping, done_stepping; | 1319 Label stepping, done_stepping; |
| 1253 | 1320 |
| 1254 // Check single stepping. | 1321 // Check single stepping. |
| 1255 __ ldr(R6, FieldAddress(CTX, Context::isolate_offset())); | 1322 __ ldr(R6, FieldAddress(CTX, Context::isolate_offset())); |
| 1256 __ ldrb(R6, Address(R6, Isolate::single_step_offset())); | 1323 __ ldrb(R6, Address(R6, Isolate::single_step_offset())); |
| 1257 __ CompareImmediate(R6, 0); | 1324 __ CompareImmediate(R6, 0); |
| 1258 __ b(&stepping, NE); | 1325 __ b(&stepping, NE); |
| 1259 __ Bind(&done_stepping); | 1326 __ Bind(&done_stepping); |
| 1260 | 1327 |
| 1328 if (kind != Token::kILLEGAL) { | |
| 1329 Label not_smi_or_overflow; | |
| 1330 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); | |
| 1331 __ Bind(¬_smi_or_overflow); | |
| 1332 } | |
| 1333 | |
| 1261 // Load arguments descriptor into R4. | 1334 // Load arguments descriptor into R4. |
| 1262 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); | 1335 __ ldr(R4, FieldAddress(R5, ICData::arguments_descriptor_offset())); |
| 1263 // Loop that checks if there is an IC data match. | 1336 // Loop that checks if there is an IC data match. |
| 1264 Label loop, update, test, found; | 1337 Label loop, update, test, found; |
| 1265 // R5: IC data object (preserved). | 1338 // R5: IC data object (preserved). |
| 1266 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); | 1339 __ ldr(R6, FieldAddress(R5, ICData::ic_data_offset())); |
| 1267 // R6: ic_data_array with check entries: classes and target functions. | 1340 // R6: ic_data_array with check entries: classes and target functions. |
| 1268 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); | 1341 __ AddImmediate(R6, R6, Array::data_offset() - kHeapObjectTag); |
| 1269 // R6: points directly to the first ic data array element. | 1342 // R6: points directly to the first ic data array element. |
| 1270 | 1343 |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1375 // LR: return address. | 1448 // LR: return address. |
| 1376 // R5: inline cache data object. | 1449 // R5: inline cache data object. |
| 1377 // Inline cache data object structure: | 1450 // Inline cache data object structure: |
| 1378 // 0: function-name | 1451 // 0: function-name |
| 1379 // 1: N, number of arguments checked. | 1452 // 1: N, number of arguments checked. |
| 1380 // 2 .. (length - 1): group of checks, each check containing: | 1453 // 2 .. (length - 1): group of checks, each check containing: |
| 1381 // - N classes. | 1454 // - N classes. |
| 1382 // - 1 target function. | 1455 // - 1 target function. |
| 1383 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1456 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1384 GenerateUsageCounterIncrement(assembler, R6); | 1457 GenerateUsageCounterIncrement(assembler, R6); |
| 1385 GenerateNArgsCheckInlineCacheStub( | 1458 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1386 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1459 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1387 } | 1460 } |
| 1388 | 1461 |
| 1389 | 1462 |
| 1390 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1463 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1391 GenerateUsageCounterIncrement(assembler, R6); | 1464 GenerateUsageCounterIncrement(assembler, R6); |
| 1392 GenerateNArgsCheckInlineCacheStub( | 1465 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1393 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1466 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1394 } | 1467 } |
| 1395 | 1468 |
| 1396 | 1469 |
| 1397 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1470 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1398 GenerateUsageCounterIncrement(assembler, R6); | 1471 GenerateUsageCounterIncrement(assembler, R6); |
| 1399 GenerateNArgsCheckInlineCacheStub( | 1472 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1400 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1473 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1474 } | |
| 1475 | |
| 1476 | |
| 1477 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { | |
| 1478 GenerateUsageCounterIncrement(assembler, R6); | |
| 1479 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1480 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); | |
| 1481 } | |
| 1482 | |
| 1483 | |
| 1484 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { | |
| 1485 GenerateUsageCounterIncrement(assembler, R6); | |
| 1486 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1487 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); | |
| 1488 } | |
| 1489 | |
| 1490 | |
| 1491 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { | |
| 1492 GenerateUsageCounterIncrement(assembler, R6); | |
| 1493 GenerateNArgsCheckInlineCacheStub(assembler, 2, | |
| 1494 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); | |
| 1401 } | 1495 } |
| 1402 | 1496 |
| 1403 | 1497 |
| 1404 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1498 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1405 Assembler* assembler) { | 1499 Assembler* assembler) { |
| 1406 GenerateOptimizedUsageCounterIncrement(assembler); | 1500 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1407 GenerateNArgsCheckInlineCacheStub( | 1501 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1408 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1502 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1409 } | 1503 } |
| 1410 | 1504 |
| 1411 | 1505 |
| 1412 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1506 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1413 Assembler* assembler) { | 1507 Assembler* assembler) { |
| 1414 GenerateOptimizedUsageCounterIncrement(assembler); | 1508 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1415 GenerateNArgsCheckInlineCacheStub( | 1509 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1416 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); | 1510 kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1417 } | 1511 } |
| 1418 | 1512 |
| 1419 | 1513 |
| 1420 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1514 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1421 Assembler* assembler) { | 1515 Assembler* assembler) { |
| 1422 GenerateOptimizedUsageCounterIncrement(assembler); | 1516 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1423 GenerateNArgsCheckInlineCacheStub( | 1517 GenerateNArgsCheckInlineCacheStub(assembler, 3, |
| 1424 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1518 kInlineCacheMissHandlerThreeArgsRuntimeEntry, Token::kILLEGAL); |
| 1425 } | 1519 } |
| 1426 | 1520 |
| 1427 | 1521 |
| 1428 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1522 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1429 GenerateNArgsCheckInlineCacheStub( | 1523 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1430 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); | 1524 kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1431 } | 1525 } |
| 1432 | 1526 |
| 1433 | 1527 |
| 1434 // Intermediary stub between a static call and its target. ICData contains | 1528 // Intermediary stub between a static call and its target. ICData contains |
| 1435 // the target function and the call count. | 1529 // the target function and the call count. |
| 1436 // R5: ICData | 1530 // R5: ICData |
| 1437 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1531 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1438 GenerateUsageCounterIncrement(assembler, R6); | 1532 GenerateUsageCounterIncrement(assembler, R6); |
| 1439 #if defined(DEBUG) | 1533 #if defined(DEBUG) |
| 1440 { Label ok; | 1534 { Label ok; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1490 | 1584 |
| 1491 // R0: function. | 1585 // R0: function. |
| 1492 // R2: target instructions. | 1586 // R2: target instructions. |
| 1493 __ AddImmediate(R2, Instructions::HeaderSize() - kHeapObjectTag); | 1587 __ AddImmediate(R2, Instructions::HeaderSize() - kHeapObjectTag); |
| 1494 __ bx(R2); | 1588 __ bx(R2); |
| 1495 } | 1589 } |
| 1496 | 1590 |
| 1497 | 1591 |
| 1498 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1592 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1499 GenerateUsageCounterIncrement(assembler, R6); | 1593 GenerateUsageCounterIncrement(assembler, R6); |
| 1500 GenerateNArgsCheckInlineCacheStub( | 1594 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1501 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry); | 1595 kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1502 } | 1596 } |
| 1503 | 1597 |
| 1504 | 1598 |
| 1505 // Stub for compiling a function and jumping to the compiled code. | 1599 // Stub for compiling a function and jumping to the compiled code. |
| 1506 // R5: IC-Data (for methods). | 1600 // R5: IC-Data (for methods). |
| 1507 // R4: Arguments descriptor. | 1601 // R4: Arguments descriptor. |
| 1508 // R0: Function. | 1602 // R0: Function. |
| 1509 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1603 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1510 // Preserve arg desc. and IC data object. | 1604 // Preserve arg desc. and IC data object. |
| 1511 __ EnterStubFrame(); | 1605 __ EnterStubFrame(); |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1856 const Register right = R0; | 1950 const Register right = R0; |
| 1857 __ ldr(left, Address(SP, 1 * kWordSize)); | 1951 __ ldr(left, Address(SP, 1 * kWordSize)); |
| 1858 __ ldr(right, Address(SP, 0 * kWordSize)); | 1952 __ ldr(right, Address(SP, 0 * kWordSize)); |
| 1859 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); | 1953 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1860 __ Ret(); | 1954 __ Ret(); |
| 1861 } | 1955 } |
| 1862 | 1956 |
| 1863 } // namespace dart | 1957 } // namespace dart |
| 1864 | 1958 |
| 1865 #endif // defined TARGET_ARCH_ARM | 1959 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |