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

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

Issue 2647913002: Optimizations to IC stub for unoptimized code performance on x64. (Closed)
Patch Set: Feedback from Regis Created 3 years, 11 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
« no previous file with comments | « runtime/vm/stub_code_arm64.cc ('k') | runtime/vm/stub_code_mips.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 1241 matching lines...) Expand 10 before | Expand all | Expand 10 after
1252 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid))); 1252 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid)));
1253 __ cmpl(Address(EBX, 0 * kWordSize), imm_smi_cid); 1253 __ cmpl(Address(EBX, 0 * kWordSize), imm_smi_cid);
1254 __ j(NOT_EQUAL, &error, Assembler::kNearJump); 1254 __ j(NOT_EQUAL, &error, Assembler::kNearJump);
1255 __ cmpl(Address(EBX, 1 * kWordSize), imm_smi_cid); 1255 __ cmpl(Address(EBX, 1 * kWordSize), imm_smi_cid);
1256 __ j(EQUAL, &ok, Assembler::kNearJump); 1256 __ j(EQUAL, &ok, Assembler::kNearJump);
1257 __ Bind(&error); 1257 __ Bind(&error);
1258 __ Stop("Incorrect IC data"); 1258 __ Stop("Incorrect IC data");
1259 __ Bind(&ok); 1259 __ Bind(&ok);
1260 #endif 1260 #endif
1261 if (FLAG_optimization_counter_threshold >= 0) { 1261 if (FLAG_optimization_counter_threshold >= 0) {
1262 // Update counter.
1263 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; 1262 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1264 __ movl(ECX, Address(EBX, count_offset)); 1263 // Update counter, ignore overflow.
1265 __ addl(ECX, Immediate(Smi::RawValue(1))); 1264 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
1266 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
1267 __ cmovno(EDI, ECX);
1268 __ StoreIntoSmiField(Address(EBX, count_offset), EDI);
1269 } 1265 }
1270 __ ret(); 1266 __ ret();
1271 } 1267 }
1272 1268
1273 1269
1274 // Generate inline cache check for 'num_args'. 1270 // Generate inline cache check for 'num_args'.
1275 // ECX: Inline cache data object. 1271 // ECX: Inline cache data object.
1276 // TOS(0): return address 1272 // TOS(0): return address
1277 // Control flow: 1273 // Control flow:
1278 // - If receiver is null -> jump to IC miss. 1274 // - If receiver is null -> jump to IC miss.
1279 // - If receiver is Smi -> load Smi class. 1275 // - If receiver is Smi -> load Smi class.
1280 // - If receiver is not-Smi -> load receiver's class. 1276 // - If receiver is not-Smi -> load receiver's class.
1281 // - Check if 'num_args' (including receiver) match any IC data group. 1277 // - Check if 'num_args' (including receiver) match any IC data group.
1282 // - Match found -> jump to target. 1278 // - Match found -> jump to target.
1283 // - Match not found -> jump to IC miss. 1279 // - Match not found -> jump to IC miss.
1284 void StubCode::GenerateNArgsCheckInlineCacheStub( 1280 void StubCode::GenerateNArgsCheckInlineCacheStub(
1285 Assembler* assembler, 1281 Assembler* assembler,
1286 intptr_t num_args, 1282 intptr_t num_args,
1287 const RuntimeEntry& handle_ic_miss, 1283 const RuntimeEntry& handle_ic_miss,
1288 Token::Kind kind, 1284 Token::Kind kind,
1289 bool optimized) { 1285 bool optimized) {
1290 ASSERT(num_args > 0); 1286 ASSERT(num_args == 1 || num_args == 2);
1291 #if defined(DEBUG) 1287 #if defined(DEBUG)
1292 { 1288 {
1293 Label ok; 1289 Label ok;
1294 // Check that the IC data array has NumArgsTested() == num_args. 1290 // Check that the IC data array has NumArgsTested() == num_args.
1295 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. 1291 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'.
1296 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset())); 1292 __ movl(EBX, FieldAddress(ECX, ICData::state_bits_offset()));
1297 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. 1293 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed.
1298 __ andl(EBX, Immediate(ICData::NumArgsTestedMask())); 1294 __ andl(EBX, Immediate(ICData::NumArgsTestedMask()));
1299 __ cmpl(EBX, Immediate(num_args)); 1295 __ cmpl(EBX, Immediate(num_args));
1300 __ j(EQUAL, &ok, Assembler::kNearJump); 1296 __ j(EQUAL, &ok, Assembler::kNearJump);
(...skipping 14 matching lines...) Expand all
1315 if (kind != Token::kILLEGAL) { 1311 if (kind != Token::kILLEGAL) {
1316 EmitFastSmiOp(assembler, kind, num_args, &not_smi_or_overflow); 1312 EmitFastSmiOp(assembler, kind, num_args, &not_smi_or_overflow);
1317 } 1313 }
1318 __ Bind(&not_smi_or_overflow); 1314 __ Bind(&not_smi_or_overflow);
1319 1315
1320 __ Comment("Extract ICData initial values and receiver cid"); 1316 __ Comment("Extract ICData initial values and receiver cid");
1321 // ECX: IC data object (preserved). 1317 // ECX: IC data object (preserved).
1322 // Load arguments descriptor into EDX. 1318 // Load arguments descriptor into EDX.
1323 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); 1319 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset()));
1324 // Loop that checks if there is an IC data match. 1320 // Loop that checks if there is an IC data match.
1321 Label loop, found, miss;
1325 // ECX: IC data object (preserved). 1322 // ECX: IC data object (preserved).
1326 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); 1323 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset()));
1327 // EBX: ic_data_array with check entries: classes and target functions. 1324 // EBX: ic_data_array with check entries: classes and target functions.
1328 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); 1325 __ leal(EBX, FieldAddress(EBX, Array::data_offset()));
1329 // EBX: points directly to the first ic data array element. 1326 // EBX: points directly to the first ic data array element.
1330 1327
1331 // Get the receiver's class ID (first read number of arguments from 1328 // Get argument descriptor into EAX. In the 1-argument case this is the
1332 // arguments descriptor array and then access the receiver from the stack). 1329 // last time we need the argument descriptor, and we reuse EAX for the
1330 // class IDs from the IC descriptor. In the 2-argument case we preserve
1331 // the argument descriptor in EAX.
1333 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); 1332 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
1334 __ movl(EDI, Address(ESP, EAX, TIMES_2, 0)); // EAX (argument_count) is smi. 1333 if (num_args == 1) {
1335 __ LoadTaggedClassIdMayBeSmi(EAX, EDI); 1334 // Load first argument into EDI.
1336 1335 __ movl(EDI,
1337 // EAX: receiver's class ID (smi). 1336 Address(ESP, EAX, TIMES_2, 0)); // EAX (argument count) is Smi.
1338 __ movl(EDI, Address(EBX, 0)); // First class id (smi) to check. 1337 __ LoadTaggedClassIdMayBeSmi(EAX, EDI);
1339 Label loop, update, test, found; 1338 // EAX: first argument class ID as Smi.
1340 __ jmp(&test); 1339 __ movl(EDI, Address(EBX, 0));
1340 }
1341 1341
1342 __ Comment("ICData loop"); 1342 __ Comment("ICData loop");
1343
1344 // We unroll the generic one that is generated once more than the others.
1345 bool optimize = kind == Token::kILLEGAL;
1346 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
1347 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1348
1343 __ Bind(&loop); 1349 __ Bind(&loop);
1344 for (int i = 0; i < num_args; i++) { 1350 for (int unroll = optimize ? 4 : 2; unroll >= 0; unroll--) {
1345 if (i > 0) { 1351 Label update;
1346 // If not the first, load the next argument's class ID. 1352 for (int i = 0; i < num_args; i++) {
1347 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); 1353 if (num_args == 2) {
1348 __ movl(EDI, Address(ESP, EAX, TIMES_2, -i * kWordSize)); 1354 // Load ith argument into EDI.
1349 __ LoadTaggedClassIdMayBeSmi(EAX, EDI); 1355 __ movl(EDI, Address(ESP, EAX, TIMES_2, -kWordSize * i));
1356 __ LoadTaggedClassIdMayBeSmi(EDI, EDI);
1357 // EDI: ith argument class ID (smi).
1358 __ cmpl(EDI, Address(EBX, kWordSize * i)); // Class id match?
1359 } else {
1360 __ cmpl(EDI, EAX); // Class id match?
1361 }
1362 if (i < (num_args - 1)) {
1363 __ j(NOT_EQUAL, &update); // Continue.
1364 } else {
1365 // Last check, all checks before matched.
1366 __ j(EQUAL, &found); // Break.
1367 }
1368 }
1369 __ Bind(&update);
1350 1370
1351 // EAX: next argument class ID (smi). 1371 const intptr_t entry_size =
1352 __ movl(EDI, Address(EBX, i * kWordSize)); 1372 ICData::TestEntryLengthFor(num_args) * kWordSize;
1353 // EDI: next class ID to check (smi). 1373 __ addl(EBX, Immediate(entry_size)); // Next entry.
1374 if (num_args == 2) {
1375 __ cmpl(Address(EBX, -entry_size),
1376 Immediate(Smi::RawValue(kIllegalCid))); // Done?
1377 } else {
1378 __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid))); // Done?
1379 __ movl(EDI, Address(EBX, 0));
1354 } 1380 }
1355 __ cmpl(EAX, EDI); // Class id match? 1381 if (unroll == 0) {
1356 if (i < (num_args - 1)) { 1382 __ j(NOT_EQUAL, &loop);
1357 __ j(NOT_EQUAL, &update); // Continue.
1358 } else { 1383 } else {
1359 // Last check, all checks before matched. 1384 __ j(EQUAL, &miss);
1360 __ j(EQUAL, &found); // Break.
1361 } 1385 }
1362 } 1386 }
1363 __ Bind(&update);
1364 // Reload receiver class ID. It has not been destroyed when num_args == 1.
1365 if (num_args > 1) {
1366 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
1367 __ movl(EDI, Address(ESP, EAX, TIMES_2, 0));
1368 __ LoadTaggedClassIdMayBeSmi(EAX, EDI);
1369 }
1370 1387
1371 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; 1388 __ Bind(&miss);
1372 __ addl(EBX, Immediate(entry_size)); // Next entry.
1373 __ movl(EDI, Address(EBX, 0)); // Next class ID.
1374
1375 __ Bind(&test);
1376 __ cmpl(EDI, Immediate(Smi::RawValue(kIllegalCid))); // Done?
1377 __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
1378
1379 __ Comment("IC miss"); 1389 __ Comment("IC miss");
1380 // Compute address of arguments (first read number of arguments from 1390 // Compute address of arguments (first read number of arguments from
1381 // arguments descriptor array and then compute address on the stack). 1391 // arguments descriptor array and then compute address on the stack).
1382 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset())); 1392 __ movl(EAX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
1383 __ leal(EAX, Address(ESP, EAX, TIMES_2, 0)); // EAX is Smi. 1393 __ leal(EAX, Address(ESP, EAX, TIMES_2, 0)); // EAX is Smi.
1384 // Create a stub frame as we are pushing some objects on the stack before 1394 // Create a stub frame as we are pushing some objects on the stack before
1385 // calling into the runtime. 1395 // calling into the runtime.
1386 __ EnterStubFrame(); 1396 __ EnterStubFrame();
1387 __ pushl(EDX); // Preserve arguments descriptor array. 1397 __ pushl(EDX); // Preserve arguments descriptor array.
1388 __ pushl(ECX); // Preserve IC data object. 1398 __ pushl(ECX); // Preserve IC data object.
(...skipping 16 matching lines...) Expand all
1405 Label call_target_function; 1415 Label call_target_function;
1406 if (!FLAG_lazy_dispatchers) { 1416 if (!FLAG_lazy_dispatchers) {
1407 GenerateDispatcherCode(assembler, &call_target_function); 1417 GenerateDispatcherCode(assembler, &call_target_function);
1408 } else { 1418 } else {
1409 __ jmp(&call_target_function); 1419 __ jmp(&call_target_function);
1410 } 1420 }
1411 1421
1412 __ Bind(&found); 1422 __ Bind(&found);
1413 1423
1414 // EBX: Pointer to an IC data check group. 1424 // EBX: Pointer to an IC data check group.
1415 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
1416 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1417 if (FLAG_optimization_counter_threshold >= 0) { 1425 if (FLAG_optimization_counter_threshold >= 0) {
1418 __ Comment("Update caller's counter"); 1426 __ Comment("Update caller's counter");
1419 __ movl(EAX, Address(EBX, count_offset)); 1427 // Ignore overflow.
1420 __ addl(EAX, Immediate(Smi::RawValue(1))); 1428 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
1421 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
1422 __ cmovno(EDI, EAX);
1423 __ StoreIntoSmiField(Address(EBX, count_offset), EDI);
1424 } 1429 }
1425 1430
1426 __ movl(EAX, Address(EBX, target_offset)); 1431 __ movl(EAX, Address(EBX, target_offset));
1427 __ Bind(&call_target_function); 1432 __ Bind(&call_target_function);
1428 __ Comment("Call target"); 1433 __ Comment("Call target");
1429 // EAX: Target function. 1434 // EAX: Target function.
1430 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset())); 1435 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset()));
1431 __ jmp(EBX); 1436 __ jmp(EBX);
1432 1437
1433 if (FLAG_support_debugger && !optimized) { 1438 if (FLAG_support_debugger && !optimized) {
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1548 1553
1549 // ECX: IC data object (preserved). 1554 // ECX: IC data object (preserved).
1550 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset())); 1555 __ movl(EBX, FieldAddress(ECX, ICData::ic_data_offset()));
1551 // EBX: ic_data_array with entries: target functions and count. 1556 // EBX: ic_data_array with entries: target functions and count.
1552 __ leal(EBX, FieldAddress(EBX, Array::data_offset())); 1557 __ leal(EBX, FieldAddress(EBX, Array::data_offset()));
1553 // EBX: points directly to the first ic data array element. 1558 // EBX: points directly to the first ic data array element.
1554 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; 1559 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize;
1555 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; 1560 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
1556 1561
1557 if (FLAG_optimization_counter_threshold >= 0) { 1562 if (FLAG_optimization_counter_threshold >= 0) {
1558 // Increment count for this call. 1563 // Increment count for this call, ignore overflow.
1559 __ movl(EAX, Address(EBX, count_offset)); 1564 __ addl(Address(EBX, count_offset), Immediate(Smi::RawValue(1)));
1560 __ addl(EAX, Immediate(Smi::RawValue(1)));
1561 __ movl(EDI, Immediate(Smi::RawValue(Smi::kMaxValue)));
1562 __ cmovno(EDI, EAX);
1563 __ StoreIntoSmiField(Address(EBX, count_offset), EDI);
1564 } 1565 }
1565 1566
1566 // Load arguments descriptor into EDX. 1567 // Load arguments descriptor into EDX.
1567 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset())); 1568 __ movl(EDX, FieldAddress(ECX, ICData::arguments_descriptor_offset()));
1568 1569
1569 // Get function and call it, if possible. 1570 // Get function and call it, if possible.
1570 __ movl(EAX, Address(EBX, target_offset)); 1571 __ movl(EAX, Address(EBX, target_offset));
1571 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset())); 1572 __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset()));
1572 __ jmp(EBX); 1573 __ jmp(EBX);
1573 1574
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
2087 } 2088 }
2088 2089
2089 2090
2090 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { 2091 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) {
2091 __ int3(); 2092 __ int3();
2092 } 2093 }
2093 2094
2094 } // namespace dart 2095 } // namespace dart
2095 2096
2096 #endif // defined TARGET_ARCH_IA32 2097 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « runtime/vm/stub_code_arm64.cc ('k') | runtime/vm/stub_code_mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698