Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: runtime/vm/stub_code_arm.cc

Issue 436643002: Faster IC stubs by specializing them for Binary Smi operations (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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, &not_smi_or_overflow);
1331 __ Bind(&not_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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698