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