| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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" // Needed here to get TARGET_ARCH_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/code_generator.h" | 8 #include "vm/code_generator.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 1247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1258 return &cls; | 1258 return &cls; |
| 1259 } | 1259 } |
| 1260 | 1260 |
| 1261 | 1261 |
| 1262 // Instance to test is in EAX. Test if its class is in subtype test cache array | 1262 // Instance to test is in EAX. Test if its class is in subtype test cache array |
| 1263 // and use the result in the array to jump to one of the labels. Fall through | 1263 // and use the result in the array to jump to one of the labels. Fall through |
| 1264 // if the instance is not in the cache array. | 1264 // if the instance is not in the cache array. |
| 1265 // TODO(srdjan): Implement a quicker subtype check, as type test | 1265 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 1266 // arrays can grow too high, but they may be useful when optimizing | 1266 // arrays can grow too high, but they may be useful when optimizing |
| 1267 // code (type-feedback). | 1267 // code (type-feedback). |
| 1268 void CodeGenerator::GenerateSubtype1TestCacheLookup( | 1268 RawSubtypeTestCache* CodeGenerator::GenerateSubtype1TestCacheLookup( |
| 1269 intptr_t node_id, | 1269 intptr_t node_id, |
| 1270 intptr_t token_index, | 1270 intptr_t token_index, |
| 1271 const Class& type_class, | 1271 const Class& type_class, |
| 1272 Label* is_instance_lbl, | 1272 Label* is_instance_lbl, |
| 1273 Label* is_not_instance_lbl) { | 1273 Label* is_not_instance_lbl) { |
| 1274 const SubtypeTestCache& type_test_cache = |
| 1275 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1274 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1276 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1275 const Immediate raw_null = | 1277 const Immediate raw_null = |
| 1276 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1278 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1277 Label loop, found_in_cache, runtime_call; | 1279 Label loop, found_in_cache, runtime_call; |
| 1278 // Check immediate equality. | 1280 // Check immediate equality. |
| 1279 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1281 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1280 // ECX: instance class. | 1282 // ECX: instance class. |
| 1281 __ CompareObject(ECX, type_class); | 1283 __ CompareObject(ECX, type_class); |
| 1282 __ j(EQUAL, is_instance_lbl); | 1284 __ j(EQUAL, is_instance_lbl); |
| 1283 | 1285 |
| 1284 // Check immediate superclass equality. | 1286 // Check immediate superclass equality. |
| 1285 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 1287 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 1286 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 1288 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 1287 __ CompareObject(EDI, type_class); | 1289 __ CompareObject(EDI, type_class); |
| 1288 __ j(EQUAL, is_instance_lbl); | 1290 __ j(EQUAL, is_instance_lbl); |
| 1289 | 1291 |
| 1290 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1292 __ LoadObject(EDX, type_test_cache); |
| 1291 __ LoadObject(EDX, Array::ZoneHandle( | |
| 1292 Array::New(SubTypeTestCache::kNumEntries))); | |
| 1293 __ pushl(EDX); // Cache array. | 1293 __ pushl(EDX); // Cache array. |
| 1294 __ pushl(EAX); // Instance. | 1294 __ pushl(EAX); // Instance. |
| 1295 __ pushl(raw_null); // Unused | 1295 __ pushl(raw_null); // Unused |
| 1296 __ call(&StubCode::Subtype1TestCacheLabel()); | 1296 __ call(&StubCode::Subtype1TestCacheLabel()); |
| 1297 __ popl(EAX); // Discard. | 1297 __ popl(EAX); // Discard. |
| 1298 __ popl(EAX); // Restore receiver. | 1298 __ popl(EAX); // Restore receiver. |
| 1299 __ popl(EDX); // Discard. | 1299 __ popl(EDX); // Discard. |
| 1300 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 1300 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1301 | 1301 |
| 1302 __ cmpl(ECX, raw_null); | 1302 __ cmpl(ECX, raw_null); |
| 1303 __ j(EQUAL, &runtime_call, Assembler::kNearJump); | 1303 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 1304 __ CompareObject(ECX, bool_true); | 1304 __ CompareObject(ECX, bool_true); |
| 1305 __ j(EQUAL, is_instance_lbl); | 1305 __ j(EQUAL, is_instance_lbl); |
| 1306 __ jmp(is_not_instance_lbl); | 1306 __ jmp(is_not_instance_lbl); |
| 1307 __ Bind(&runtime_call); | 1307 __ Bind(&runtime_call); |
| 1308 return type_test_cache.raw(); |
| 1308 } | 1309 } |
| 1309 | 1310 |
| 1310 | 1311 |
| 1311 // Inline tests according to the 'type' being tested. Jump to labels | 1312 // Inline tests according to the 'type' being tested. Jump to labels |
| 1312 // if we can compute the type-test, otherwise fallthrough. | 1313 // if we can compute the type-test, otherwise fallthrough. |
| 1313 // EAX: instance to be tested, must be preserved. | 1314 // EAX: instance to be tested, must be preserved. |
| 1314 // Clobbers many registers. | 1315 // Clobbers many registers. |
| 1315 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id, | 1316 RawSubtypeTestCache* CodeGenerator::GenerateInlineInstanceof( |
| 1316 intptr_t token_index, | 1317 intptr_t node_id, |
| 1317 const AbstractType& type, | 1318 intptr_t token_index, |
| 1318 Label* is_instance_lbl, | 1319 const AbstractType& type, |
| 1319 Label* is_not_instance_lbl) { | 1320 Label* is_instance_lbl, |
| 1321 Label* is_not_instance_lbl) { |
| 1320 if (type.IsInstantiated()) { | 1322 if (type.IsInstantiated()) { |
| 1321 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1323 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1322 // A Smi object cannot be the instance of a parameterized class. | 1324 // A Smi object cannot be the instance of a parameterized class. |
| 1323 // A class equality check is only applicable with a dst type of a | 1325 // A class equality check is only applicable with a dst type of a |
| 1324 // non-parameterized class or with a raw dst type of a parameterized class. | 1326 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1325 if (type_class.HasTypeArguments()) { | 1327 if (type_class.HasTypeArguments()) { |
| 1326 GenerateInstantiatedTypeWithArgumentsTest(node_id, | 1328 return GenerateInstantiatedTypeWithArgumentsTest(node_id, |
| 1327 token_index, | 1329 token_index, |
| 1328 type, | 1330 type, |
| 1329 is_instance_lbl, | 1331 is_instance_lbl, |
| 1330 is_not_instance_lbl); | 1332 is_not_instance_lbl); |
| 1331 // Fall through to runtime call. | 1333 // Fall through to runtime call. |
| 1332 } else { | 1334 } else { |
| 1333 GenerateInstantiatedTypeNoArgumentsTest(node_id, | 1335 GenerateInstantiatedTypeNoArgumentsTest(node_id, |
| 1334 token_index, | 1336 token_index, |
| 1335 type, | 1337 type, |
| 1336 is_instance_lbl, | 1338 is_instance_lbl, |
| 1337 is_not_instance_lbl); | 1339 is_not_instance_lbl); |
| 1338 // If test non-conclusive so far, try the inlined type-test cache. | 1340 // If test non-conclusive so far, try the inlined type-test cache. |
| 1339 // 'type' is known at compile time. | 1341 // 'type' is known at compile time. |
| 1340 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1342 return GenerateSubtype1TestCacheLookup( |
| 1341 is_instance_lbl, is_not_instance_lbl); | 1343 node_id, token_index, type_class, |
| 1344 is_instance_lbl, is_not_instance_lbl); |
| 1342 } | 1345 } |
| 1343 } else { | 1346 } else { |
| 1344 GenerateUninstantiatedTypeTest(type, | 1347 GenerateUninstantiatedTypeTest(type, |
| 1345 token_index, | 1348 token_index, |
| 1346 is_instance_lbl); | 1349 is_instance_lbl); |
| 1347 } | 1350 } |
| 1351 return SubtypeTestCache::null(); |
| 1348 } | 1352 } |
| 1349 | 1353 |
| 1350 | 1354 |
| 1351 // If instanceof type test cannot be performed successfully at compile time and | 1355 // If instanceof type test cannot be performed successfully at compile time and |
| 1352 // therefore eliminated, optimize it by adding inlined tests for: | 1356 // therefore eliminated, optimize it by adding inlined tests for: |
| 1353 // - NULL -> return false. | 1357 // - NULL -> return false. |
| 1354 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1358 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1355 // - Class equality (only if class is not parameterized). | 1359 // - Class equality (only if class is not parameterized). |
| 1356 // Inputs: | 1360 // Inputs: |
| 1357 // - EAX: object. | 1361 // - EAX: object. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1418 // We can only inline this null check if the type is instantiated at compile | 1422 // We can only inline this null check if the type is instantiated at compile |
| 1419 // time, since an uninstantiated type at compile time could be Object or | 1423 // time, since an uninstantiated type at compile time could be Object or |
| 1420 // Dynamic at run time. | 1424 // Dynamic at run time. |
| 1421 Label non_null; | 1425 Label non_null; |
| 1422 __ cmpl(EAX, raw_null); | 1426 __ cmpl(EAX, raw_null); |
| 1423 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); | 1427 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); |
| 1424 __ PushObject(negate_result ? bool_true : bool_false); | 1428 __ PushObject(negate_result ? bool_true : bool_false); |
| 1425 __ jmp(&done); | 1429 __ jmp(&done); |
| 1426 __ Bind(&non_null); | 1430 __ Bind(&non_null); |
| 1427 } | 1431 } |
| 1428 | 1432 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 1429 GenerateInlineInstanceof(node_id, token_index, type, | 1433 test_cache = GenerateInlineInstanceof(node_id, token_index, type, |
| 1430 &is_instance_of, &is_not_instance_of); | 1434 &is_instance_of, &is_not_instance_of); |
| 1431 | 1435 |
| 1432 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1436 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1433 const Immediate location = Immediate(Smi::RawValue(token_index)); | 1437 const Immediate location = Immediate(Smi::RawValue(token_index)); |
| 1434 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id)); | 1438 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id)); |
| 1435 __ pushl(location); // Push the source location. | 1439 __ pushl(location); // Push the source location. |
| 1436 __ pushl(node_id_as_smi); // node-id. | 1440 __ pushl(node_id_as_smi); // node-id. |
| 1437 __ pushl(EAX); // Push the instance. | 1441 __ pushl(EAX); // Push the instance. |
| 1438 __ PushObject(type); // Push the type. | 1442 __ PushObject(type); // Push the type. |
| 1439 if (!type.IsInstantiated()) { | 1443 if (!type.IsInstantiated()) { |
| 1440 GenerateInstantiatorTypeArguments(token_index); | 1444 GenerateInstantiatorTypeArguments(token_index); |
| 1441 } else { | 1445 } else { |
| 1442 __ pushl(raw_null); // Null instantiator. | 1446 __ pushl(raw_null); // Null instantiator. |
| 1443 } | 1447 } |
| 1448 __ LoadObject(EAX, test_cache); |
| 1449 __ pushl(EAX); |
| 1444 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1450 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1445 // Pop the two parameters supplied to the runtime entry. The result of the | 1451 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1446 // instanceof runtime call will be left as the result of the operation. | 1452 // instanceof runtime call will be left as the result of the operation. |
| 1447 __ addl(ESP, Immediate(5 * kWordSize)); | 1453 __ addl(ESP, Immediate(6 * kWordSize)); |
| 1448 if (negate_result) { | 1454 if (negate_result) { |
| 1449 __ popl(EDX); | 1455 __ popl(EDX); |
| 1450 __ CompareObject(EDX, bool_false); | 1456 __ CompareObject(EDX, bool_false); |
| 1451 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump); | 1457 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump); |
| 1452 // Fall through to is_instance_of. | 1458 // Fall through to is_instance_of. |
| 1453 } else { | 1459 } else { |
| 1454 __ jmp(&done); | 1460 __ jmp(&done); |
| 1455 } | 1461 } |
| 1456 | 1462 |
| 1457 __ Bind(&is_instance_of); | 1463 __ Bind(&is_instance_of); |
| 1458 __ PushObject(negate_result ? bool_false: bool_true); | 1464 __ PushObject(negate_result ? bool_false: bool_true); |
| 1459 __ jmp(&done, Assembler::kNearJump); | 1465 __ jmp(&done, Assembler::kNearJump); |
| 1460 __ Bind(&is_not_instance_of); | 1466 __ Bind(&is_not_instance_of); |
| 1461 __ PushObject(negate_result ? bool_true: bool_false); | 1467 __ PushObject(negate_result ? bool_true: bool_false); |
| 1462 __ Bind(&done); | 1468 __ Bind(&done); |
| 1463 } | 1469 } |
| 1464 | 1470 |
| 1465 | 1471 |
| 1466 // EAX: instance to test. | 1472 // EAX: instance to test. |
| 1467 // Clobbers: ECX. | 1473 // Clobbers: ECX. |
| 1468 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 1474 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 1469 // type test is conclusive, otherwise fallthrough if a type test could not | 1475 // type test is conclusive, otherwise fallthrough if a type test could not |
| 1470 // be completed. | 1476 // be completed. |
| 1471 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( | 1477 RawSubtypeTestCache* CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( |
| 1472 intptr_t node_id, | 1478 intptr_t node_id, |
| 1473 intptr_t token_index, | 1479 intptr_t token_index, |
| 1474 const AbstractType& type, | 1480 const AbstractType& type, |
| 1475 Label* is_instance_lbl, | 1481 Label* is_instance_lbl, |
| 1476 Label* is_not_instance_lbl) { | 1482 Label* is_not_instance_lbl) { |
| 1477 ASSERT(type.IsInstantiated()); | 1483 ASSERT(type.IsInstantiated()); |
| 1478 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1484 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1479 ASSERT(type_class.HasTypeArguments()); | 1485 ASSERT(type_class.HasTypeArguments()); |
| 1480 // A Smi object cannot be the instance of a parameterized class. | 1486 // A Smi object cannot be the instance of a parameterized class. |
| 1481 // A class equality check is only applicable with a dst type of a | 1487 // A class equality check is only applicable with a dst type of a |
| 1482 // non-parameterized class or with a raw dst type of a parameterized class. | 1488 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1483 __ testl(EAX, Immediate(kSmiTagMask)); | 1489 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1484 __ j(ZERO, is_not_instance_lbl); | 1490 __ j(ZERO, is_not_instance_lbl); |
| 1485 const AbstractTypeArguments& type_arguments = | 1491 const AbstractTypeArguments& type_arguments = |
| 1486 AbstractTypeArguments::ZoneHandle(type.arguments()); | 1492 AbstractTypeArguments::ZoneHandle(type.arguments()); |
| 1487 const bool is_raw_type = type_arguments.IsNull() || | 1493 const bool is_raw_type = type_arguments.IsNull() || |
| 1488 type_arguments.IsRaw(type_arguments.Length()); | 1494 type_arguments.IsRaw(type_arguments.Length()); |
| 1489 if (is_raw_type) { | 1495 if (is_raw_type) { |
| 1490 // Dynamic type argument, check only classes. | 1496 // Dynamic type argument, check only classes. |
| 1491 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1497 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1492 if (type.IsListInterface()) { | 1498 if (type.IsListInterface()) { |
| 1493 // TODO(srdjan) also accept List<Object>. | 1499 // TODO(srdjan) also accept List<Object>. |
| 1494 __ CompareObject(ECX, *CoreClass("ObjectArray")); | 1500 __ CompareObject(ECX, *CoreClass("ObjectArray")); |
| 1495 __ j(EQUAL, is_instance_lbl); | 1501 __ j(EQUAL, is_instance_lbl); |
| 1496 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | 1502 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); |
| 1497 __ j(EQUAL, is_instance_lbl); | 1503 __ j(EQUAL, is_instance_lbl); |
| 1498 } | 1504 } |
| 1499 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1505 return |
| 1500 is_instance_lbl, is_not_instance_lbl); | 1506 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1501 return; | 1507 is_instance_lbl, is_not_instance_lbl); |
| 1502 } | 1508 } |
| 1503 // Note that the test below must be synced with the tests in | 1509 // Note that the test below must be synced with the tests in |
| 1504 // CodeGenerator::UpdateTestCache. | 1510 // CodeGenerator::UpdateTestCache. |
| 1505 // Inline checks for one type argument only. | 1511 // Inline checks for one type argument only. |
| 1506 if (type_arguments.Length() != 1) { | 1512 if (type_arguments.Length() != 1) { |
| 1507 return; | 1513 return SubtypeTestCache::null(); |
| 1508 } | 1514 } |
| 1509 const AbstractType& tp_argument = | 1515 const AbstractType& tp_argument = |
| 1510 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); | 1516 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); |
| 1511 if (!tp_argument.IsType()) { | 1517 if (!tp_argument.IsType()) { |
| 1512 // E.g., it is a TypeParameter. | 1518 // E.g., it is a TypeParameter. |
| 1513 return; | 1519 return SubtypeTestCache::null(); |
| 1514 } | 1520 } |
| 1515 // Malformed type has been caught in the caller chain of this function. | 1521 // Malformed type has been caught in the caller chain of this function. |
| 1516 ASSERT(tp_argument.HasResolvedTypeClass()); | 1522 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 1517 // Check if type argument is dynamic or Object. | 1523 // Check if type argument is dynamic or Object. |
| 1518 const Type& object_type = | 1524 const Type& object_type = |
| 1519 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1525 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1520 Error& malformed_error = Error::Handle(); | 1526 Error& malformed_error = Error::Handle(); |
| 1521 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { | 1527 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 1522 // Instance class test only necessary. | 1528 // Instance class test only necessary. |
| 1523 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1529 return GenerateSubtype1TestCacheLookup( |
| 1524 is_instance_lbl, is_not_instance_lbl); | 1530 node_id, token_index, type_class, is_instance_lbl, is_not_instance_lbl); |
| 1525 return; | |
| 1526 } | 1531 } |
| 1532 const SubtypeTestCache& type_test_cache = |
| 1533 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1527 Label inlined_check, fall_through; | 1534 Label inlined_check, fall_through; |
| 1528 const Immediate raw_null = | 1535 const Immediate raw_null = |
| 1529 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1536 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1530 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1537 __ LoadObject(EDX, type_test_cache); |
| 1531 __ LoadObject(EDX, Array::ZoneHandle( | |
| 1532 Array::New(SubTypeTestCache::kNumEntries))); | |
| 1533 __ pushl(EDX); // Cache array. | 1538 __ pushl(EDX); // Cache array. |
| 1534 __ pushl(EAX); // Instance. | 1539 __ pushl(EAX); // Instance. |
| 1535 __ pushl(raw_null); // Unused. | 1540 __ pushl(raw_null); // Unused. |
| 1536 __ call(&StubCode::Subtype2TestCacheLabel()); | 1541 __ call(&StubCode::Subtype2TestCacheLabel()); |
| 1537 __ popl(EAX); // Discard. | 1542 __ popl(EAX); // Discard. |
| 1538 __ popl(EAX); // Restore receiver. | 1543 __ popl(EAX); // Restore receiver. |
| 1539 __ popl(EDX); // Discard. | 1544 __ popl(EDX); // Discard. |
| 1540 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 1545 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1541 | 1546 |
| 1542 __ cmpl(ECX, raw_null); | 1547 __ cmpl(ECX, raw_null); |
| 1543 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1548 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1544 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1549 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1545 __ CompareObject(ECX, bool_true); | 1550 __ CompareObject(ECX, bool_true); |
| 1546 __ j(EQUAL, is_instance_lbl); | 1551 __ j(EQUAL, is_instance_lbl); |
| 1547 __ jmp(is_not_instance_lbl); | 1552 __ jmp(is_not_instance_lbl); |
| 1548 __ Bind(&fall_through); | 1553 __ Bind(&fall_through); |
| 1554 return type_test_cache.raw(); |
| 1549 } | 1555 } |
| 1550 | 1556 |
| 1551 | 1557 |
| 1552 // EAX: instance to test. | 1558 // EAX: instance to test. |
| 1553 // Clobbers: EBX, ECX, EDX. | 1559 // Clobbers: EBX, ECX, EDX. |
| 1554 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( | 1560 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( |
| 1555 intptr_t node_id, | 1561 intptr_t node_id, |
| 1556 intptr_t token_index, | 1562 intptr_t token_index, |
| 1557 const AbstractType& type, | 1563 const AbstractType& type, |
| 1558 Label* is_instance_lbl, | 1564 Label* is_instance_lbl, |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1798 __ PushObject(dst_name); // Push the name of the destination. | 1804 __ PushObject(dst_name); // Push the name of the destination. |
| 1799 __ PushObject(error_message); | 1805 __ PushObject(error_message); |
| 1800 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | 1806 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1801 // We should never return here. | 1807 // We should never return here. |
| 1802 __ int3(); | 1808 __ int3(); |
| 1803 | 1809 |
| 1804 __ Bind(&done); // For a null object. | 1810 __ Bind(&done); // For a null object. |
| 1805 return; | 1811 return; |
| 1806 } | 1812 } |
| 1807 | 1813 |
| 1808 GenerateInlineInstanceof(node_id, token_index, dst_type, | 1814 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 1809 &done, &runtime_call); | 1815 test_cache = GenerateInlineInstanceof(node_id, token_index, dst_type, |
| 1816 &done, &runtime_call); |
| 1810 | 1817 |
| 1811 __ Bind(&runtime_call); | 1818 __ Bind(&runtime_call); |
| 1812 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1819 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1813 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 1820 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 1814 __ pushl(Immediate(Smi::RawValue(node_id))); // node-id. | 1821 __ pushl(Immediate(Smi::RawValue(node_id))); // node-id. |
| 1815 __ pushl(EAX); // Push the source object. | 1822 __ pushl(EAX); // Push the source object. |
| 1816 __ PushObject(dst_type); // Push the type of the destination. | 1823 __ PushObject(dst_type); // Push the type of the destination. |
| 1817 if (dst_type.IsInstantiated()) { | 1824 if (dst_type.IsInstantiated()) { |
| 1818 __ pushl(raw_null); // Null instantiator. | 1825 __ pushl(raw_null); // Null instantiator. |
| 1819 } else { | 1826 } else { |
| 1820 GenerateInstantiatorTypeArguments(token_index); | 1827 GenerateInstantiatorTypeArguments(token_index); |
| 1821 } | 1828 } |
| 1822 __ PushObject(dst_name); // Push the name of the destination. | 1829 __ PushObject(dst_name); // Push the name of the destination. |
| 1830 __ LoadObject(EAX, test_cache); |
| 1831 __ pushl(EAX); |
| 1823 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); | 1832 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); |
| 1824 // Pop the parameters supplied to the runtime entry. The result of the | 1833 // Pop the parameters supplied to the runtime entry. The result of the |
| 1825 // type check runtime call is the checked value. | 1834 // type check runtime call is the checked value. |
| 1826 __ addl(ESP, Immediate(6 * kWordSize)); | 1835 __ addl(ESP, Immediate(7 * kWordSize)); |
| 1827 __ popl(EAX); | 1836 __ popl(EAX); |
| 1828 | 1837 |
| 1829 // EAX: value. | 1838 // EAX: value. |
| 1830 __ Bind(&done); | 1839 __ Bind(&done); |
| 1831 } | 1840 } |
| 1832 | 1841 |
| 1833 | 1842 |
| 1834 void CodeGenerator::GenerateArgumentTypeChecks() { | 1843 void CodeGenerator::GenerateArgumentTypeChecks() { |
| 1835 const Function& function = parsed_function_.function(); | 1844 const Function& function = parsed_function_.function(); |
| 1836 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); | 1845 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); |
| (...skipping 1128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2965 const Error& error = Error::Handle( | 2974 const Error& error = Error::Handle( |
| 2966 Parser::FormatError(script, token_index, "Error", format, args)); | 2975 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2967 va_end(args); | 2976 va_end(args); |
| 2968 Isolate::Current()->long_jump_base()->Jump(1, error); | 2977 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2969 UNREACHABLE(); | 2978 UNREACHABLE(); |
| 2970 } | 2979 } |
| 2971 | 2980 |
| 2972 } // namespace dart | 2981 } // namespace dart |
| 2973 | 2982 |
| 2974 #endif // defined TARGET_ARCH_IA32 | 2983 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |