| 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 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 return &cls; | 1285 return &cls; |
| 1286 } | 1286 } |
| 1287 | 1287 |
| 1288 | 1288 |
| 1289 // Instance to test is in EAX. Test if its class is in subtype test cache array | 1289 // Instance to test is in EAX. Test if its class is in subtype test cache array |
| 1290 // and use the result in the array to jump to one of the labels. Fall through | 1290 // and use the result in the array to jump to one of the labels. Fall through |
| 1291 // if the instance is not in the cache array. | 1291 // if the instance is not in the cache array. |
| 1292 // TODO(srdjan): Implement a quicker subtype check, as type test | 1292 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 1293 // arrays can grow too high, but they may be useful when optimizing | 1293 // arrays can grow too high, but they may be useful when optimizing |
| 1294 // code (type-feedback). | 1294 // code (type-feedback). |
| 1295 void CodeGenerator::GenerateSubtype1TestCacheLookup( | 1295 RawSubtypeTestCache* CodeGenerator::GenerateSubtype1TestCacheLookup( |
| 1296 intptr_t node_id, | 1296 intptr_t node_id, |
| 1297 intptr_t token_index, | 1297 intptr_t token_index, |
| 1298 const Class& type_class, | 1298 const Class& type_class, |
| 1299 Label* is_instance_lbl, | 1299 Label* is_instance_lbl, |
| 1300 Label* is_not_instance_lbl) { | 1300 Label* is_not_instance_lbl) { |
| 1301 const SubtypeTestCache& type_test_cache = |
| 1302 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1301 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1303 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1302 const Immediate raw_null = | 1304 const Immediate raw_null = |
| 1303 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1305 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1304 Label loop, found_in_cache, runtime_call; | 1306 Label loop, found_in_cache, runtime_call; |
| 1305 // Check immediate equality. | 1307 // Check immediate equality. |
| 1306 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1308 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1307 // ECX: instance class. | 1309 // ECX: instance class. |
| 1308 __ CompareObject(ECX, type_class); | 1310 __ CompareObject(ECX, type_class); |
| 1309 __ j(EQUAL, is_instance_lbl); | 1311 __ j(EQUAL, is_instance_lbl); |
| 1310 | 1312 |
| 1311 // Check immediate superclass equality. | 1313 // Check immediate superclass equality. |
| 1312 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 1314 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 1313 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 1315 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 1314 __ CompareObject(EDI, type_class); | 1316 __ CompareObject(EDI, type_class); |
| 1315 __ j(EQUAL, is_instance_lbl); | 1317 __ j(EQUAL, is_instance_lbl); |
| 1316 | 1318 |
| 1317 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1319 __ LoadObject(EDX, type_test_cache); |
| 1318 __ LoadObject(EDX, Array::ZoneHandle( | |
| 1319 Array::New(SubTypeTestCache::kNumEntries))); | |
| 1320 __ pushl(EDX); // Cache array. | 1320 __ pushl(EDX); // Cache array. |
| 1321 __ pushl(EAX); // Instance. | 1321 __ pushl(EAX); // Instance. |
| 1322 __ pushl(raw_null); // Unused | 1322 __ pushl(raw_null); // Unused |
| 1323 __ call(&StubCode::Subtype1TestCacheLabel()); | 1323 __ call(&StubCode::Subtype1TestCacheLabel()); |
| 1324 __ popl(EAX); // Discard. | 1324 __ popl(EAX); // Discard. |
| 1325 __ popl(EAX); // Restore receiver. | 1325 __ popl(EAX); // Restore receiver. |
| 1326 __ popl(EDX); // Discard. | 1326 __ popl(EDX); // Discard. |
| 1327 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 1327 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1328 | 1328 |
| 1329 __ cmpl(ECX, raw_null); | 1329 __ cmpl(ECX, raw_null); |
| 1330 __ j(EQUAL, &runtime_call, Assembler::kNearJump); | 1330 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 1331 __ CompareObject(ECX, bool_true); | 1331 __ CompareObject(ECX, bool_true); |
| 1332 __ j(EQUAL, is_instance_lbl); | 1332 __ j(EQUAL, is_instance_lbl); |
| 1333 __ jmp(is_not_instance_lbl); | 1333 __ jmp(is_not_instance_lbl); |
| 1334 __ Bind(&runtime_call); | 1334 __ Bind(&runtime_call); |
| 1335 return type_test_cache.raw(); |
| 1335 } | 1336 } |
| 1336 | 1337 |
| 1337 | 1338 |
| 1338 // Inline tests according to the 'type' being tested. Jump to labels | 1339 // Inline tests according to the 'type' being tested. Jump to labels |
| 1339 // if we can compute the type-test, otherwise fallthrough. | 1340 // if we can compute the type-test, otherwise fallthrough. |
| 1340 // EAX: instance to be tested, must be preserved. | 1341 // EAX: instance to be tested, must be preserved. |
| 1341 // Clobbers many registers. | 1342 // Clobbers many registers. |
| 1342 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id, | 1343 RawSubtypeTestCache* CodeGenerator::GenerateInlineInstanceof( |
| 1343 intptr_t token_index, | 1344 intptr_t node_id, |
| 1344 const AbstractType& type, | 1345 intptr_t token_index, |
| 1345 Label* is_instance_lbl, | 1346 const AbstractType& type, |
| 1346 Label* is_not_instance_lbl) { | 1347 Label* is_instance_lbl, |
| 1348 Label* is_not_instance_lbl) { |
| 1347 if (type.IsInstantiated()) { | 1349 if (type.IsInstantiated()) { |
| 1348 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1350 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1349 // A Smi object cannot be the instance of a parameterized class. | 1351 // A Smi object cannot be the instance of a parameterized class. |
| 1350 // A class equality check is only applicable with a dst type of a | 1352 // A class equality check is only applicable with a dst type of a |
| 1351 // non-parameterized class or with a raw dst type of a parameterized class. | 1353 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1352 if (type_class.HasTypeArguments()) { | 1354 if (type_class.HasTypeArguments()) { |
| 1353 GenerateInstantiatedTypeWithArgumentsTest(node_id, | 1355 return GenerateInstantiatedTypeWithArgumentsTest(node_id, |
| 1354 token_index, | 1356 token_index, |
| 1355 type, | 1357 type, |
| 1356 is_instance_lbl, | 1358 is_instance_lbl, |
| 1357 is_not_instance_lbl); | 1359 is_not_instance_lbl); |
| 1358 // Fall through to runtime call. | 1360 // Fall through to runtime call. |
| 1359 } else { | 1361 } else { |
| 1360 GenerateInstantiatedTypeNoArgumentsTest(node_id, | 1362 GenerateInstantiatedTypeNoArgumentsTest(node_id, |
| 1361 token_index, | 1363 token_index, |
| 1362 type, | 1364 type, |
| 1363 is_instance_lbl, | 1365 is_instance_lbl, |
| 1364 is_not_instance_lbl); | 1366 is_not_instance_lbl); |
| 1365 // If test non-conclusive so far, try the inlined type-test cache. | 1367 // If test non-conclusive so far, try the inlined type-test cache. |
| 1366 // 'type' is known at compile time. | 1368 // 'type' is known at compile time. |
| 1367 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1369 return GenerateSubtype1TestCacheLookup( |
| 1368 is_instance_lbl, is_not_instance_lbl); | 1370 node_id, token_index, type_class, |
| 1371 is_instance_lbl, is_not_instance_lbl); |
| 1369 } | 1372 } |
| 1370 } else { | 1373 } else { |
| 1371 GenerateUninstantiatedTypeTest(type, | 1374 GenerateUninstantiatedTypeTest(type, |
| 1372 token_index, | 1375 token_index, |
| 1373 is_instance_lbl); | 1376 is_instance_lbl); |
| 1374 } | 1377 } |
| 1378 return SubtypeTestCache::null(); |
| 1375 } | 1379 } |
| 1376 | 1380 |
| 1377 | 1381 |
| 1378 // If instanceof type test cannot be performed successfully at compile time and | 1382 // If instanceof type test cannot be performed successfully at compile time and |
| 1379 // therefore eliminated, optimize it by adding inlined tests for: | 1383 // therefore eliminated, optimize it by adding inlined tests for: |
| 1380 // - NULL -> return false. | 1384 // - NULL -> return false. |
| 1381 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1385 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1382 // - Class equality (only if class is not parameterized). | 1386 // - Class equality (only if class is not parameterized). |
| 1383 // Inputs: | 1387 // Inputs: |
| 1384 // - EAX: object. | 1388 // - EAX: object. |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1445 // We can only inline this null check if the type is instantiated at compile | 1449 // We can only inline this null check if the type is instantiated at compile |
| 1446 // time, since an uninstantiated type at compile time could be Object or | 1450 // time, since an uninstantiated type at compile time could be Object or |
| 1447 // Dynamic at run time. | 1451 // Dynamic at run time. |
| 1448 Label non_null; | 1452 Label non_null; |
| 1449 __ cmpl(EAX, raw_null); | 1453 __ cmpl(EAX, raw_null); |
| 1450 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); | 1454 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); |
| 1451 __ PushObject(negate_result ? bool_true : bool_false); | 1455 __ PushObject(negate_result ? bool_true : bool_false); |
| 1452 __ jmp(&done); | 1456 __ jmp(&done); |
| 1453 __ Bind(&non_null); | 1457 __ Bind(&non_null); |
| 1454 } | 1458 } |
| 1455 | 1459 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 1456 GenerateInlineInstanceof(node_id, token_index, type, | 1460 test_cache = GenerateInlineInstanceof(node_id, token_index, type, |
| 1457 &is_instance_of, &is_not_instance_of); | 1461 &is_instance_of, &is_not_instance_of); |
| 1458 | 1462 |
| 1459 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1463 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1460 const Immediate location = Immediate(Smi::RawValue(token_index)); | 1464 const Immediate location = Immediate(Smi::RawValue(token_index)); |
| 1461 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id)); | 1465 const Immediate node_id_as_smi = Immediate(Smi::RawValue(node_id)); |
| 1462 __ pushl(location); // Push the source location. | 1466 __ pushl(location); // Push the source location. |
| 1463 __ pushl(node_id_as_smi); // node-id. | 1467 __ pushl(node_id_as_smi); // node-id. |
| 1464 __ pushl(EAX); // Push the instance. | 1468 __ pushl(EAX); // Push the instance. |
| 1465 __ PushObject(type); // Push the type. | 1469 __ PushObject(type); // Push the type. |
| 1466 if (!type.IsInstantiated()) { | 1470 if (!type.IsInstantiated()) { |
| 1467 GenerateInstantiatorTypeArguments(token_index); | 1471 GenerateInstantiatorTypeArguments(token_index); |
| 1468 } else { | 1472 } else { |
| 1469 __ pushl(raw_null); // Null instantiator. | 1473 __ pushl(raw_null); // Null instantiator. |
| 1470 } | 1474 } |
| 1475 __ LoadObject(EAX, test_cache); |
| 1476 __ pushl(EAX); |
| 1471 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1477 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1472 // Pop the two parameters supplied to the runtime entry. The result of the | 1478 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1473 // instanceof runtime call will be left as the result of the operation. | 1479 // instanceof runtime call will be left as the result of the operation. |
| 1474 __ addl(ESP, Immediate(5 * kWordSize)); | 1480 __ addl(ESP, Immediate(6 * kWordSize)); |
| 1475 if (negate_result) { | 1481 if (negate_result) { |
| 1476 __ popl(EDX); | 1482 __ popl(EDX); |
| 1477 __ CompareObject(EDX, bool_false); | 1483 __ CompareObject(EDX, bool_false); |
| 1478 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump); | 1484 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump); |
| 1479 // Fall through to is_instance_of. | 1485 // Fall through to is_instance_of. |
| 1480 } else { | 1486 } else { |
| 1481 __ jmp(&done); | 1487 __ jmp(&done); |
| 1482 } | 1488 } |
| 1483 | 1489 |
| 1484 __ Bind(&is_instance_of); | 1490 __ Bind(&is_instance_of); |
| 1485 __ PushObject(negate_result ? bool_false: bool_true); | 1491 __ PushObject(negate_result ? bool_false: bool_true); |
| 1486 __ jmp(&done, Assembler::kNearJump); | 1492 __ jmp(&done, Assembler::kNearJump); |
| 1487 __ Bind(&is_not_instance_of); | 1493 __ Bind(&is_not_instance_of); |
| 1488 __ PushObject(negate_result ? bool_true: bool_false); | 1494 __ PushObject(negate_result ? bool_true: bool_false); |
| 1489 __ Bind(&done); | 1495 __ Bind(&done); |
| 1490 } | 1496 } |
| 1491 | 1497 |
| 1492 | 1498 |
| 1493 // EAX: instance to test. | 1499 // EAX: instance to test. |
| 1494 // Clobbers: ECX. | 1500 // Clobbers: ECX. |
| 1495 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 1501 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 1496 // type test is conclusive, otherwise fallthrough if a type test could not | 1502 // type test is conclusive, otherwise fallthrough if a type test could not |
| 1497 // be completed. | 1503 // be completed. |
| 1498 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( | 1504 RawSubtypeTestCache* CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( |
| 1499 intptr_t node_id, | 1505 intptr_t node_id, |
| 1500 intptr_t token_index, | 1506 intptr_t token_index, |
| 1501 const AbstractType& type, | 1507 const AbstractType& type, |
| 1502 Label* is_instance_lbl, | 1508 Label* is_instance_lbl, |
| 1503 Label* is_not_instance_lbl) { | 1509 Label* is_not_instance_lbl) { |
| 1504 ASSERT(type.IsInstantiated()); | 1510 ASSERT(type.IsInstantiated()); |
| 1505 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1511 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1506 ASSERT(type_class.HasTypeArguments()); | 1512 ASSERT(type_class.HasTypeArguments()); |
| 1507 // A Smi object cannot be the instance of a parameterized class. | 1513 // A Smi object cannot be the instance of a parameterized class. |
| 1508 // A class equality check is only applicable with a dst type of a | 1514 // A class equality check is only applicable with a dst type of a |
| 1509 // non-parameterized class or with a raw dst type of a parameterized class. | 1515 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1510 __ testl(EAX, Immediate(kSmiTagMask)); | 1516 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1511 __ j(ZERO, is_not_instance_lbl); | 1517 __ j(ZERO, is_not_instance_lbl); |
| 1512 const AbstractTypeArguments& type_arguments = | 1518 const AbstractTypeArguments& type_arguments = |
| 1513 AbstractTypeArguments::ZoneHandle(type.arguments()); | 1519 AbstractTypeArguments::ZoneHandle(type.arguments()); |
| 1514 const bool is_raw_type = type_arguments.IsNull() || | 1520 const bool is_raw_type = type_arguments.IsNull() || |
| 1515 type_arguments.IsRaw(type_arguments.Length()); | 1521 type_arguments.IsRaw(type_arguments.Length()); |
| 1516 if (is_raw_type) { | 1522 if (is_raw_type) { |
| 1517 // Dynamic type argument, check only classes. | 1523 // Dynamic type argument, check only classes. |
| 1518 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1524 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1519 if (type.IsListInterface()) { | 1525 if (type.IsListInterface()) { |
| 1520 // TODO(srdjan) also accept List<Object>. | 1526 // TODO(srdjan) also accept List<Object>. |
| 1521 __ CompareObject(ECX, *CoreClass("ObjectArray")); | 1527 __ CompareObject(ECX, *CoreClass("ObjectArray")); |
| 1522 __ j(EQUAL, is_instance_lbl); | 1528 __ j(EQUAL, is_instance_lbl); |
| 1523 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | 1529 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); |
| 1524 __ j(EQUAL, is_instance_lbl); | 1530 __ j(EQUAL, is_instance_lbl); |
| 1525 } | 1531 } |
| 1526 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1532 return |
| 1527 is_instance_lbl, is_not_instance_lbl); | 1533 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1528 return; | 1534 is_instance_lbl, is_not_instance_lbl); |
| 1529 } | 1535 } |
| 1530 // Note that the test below must be synced with the tests in | 1536 // Note that the test below must be synced with the tests in |
| 1531 // CodeGenerator::UpdateTestCache. | 1537 // CodeGenerator::UpdateTestCache. |
| 1532 // Inline checks for one type argument only. | 1538 // Inline checks for one type argument only. |
| 1533 if (type_arguments.Length() != 1) { | 1539 if (type_arguments.Length() != 1) { |
| 1534 return; | 1540 return SubtypeTestCache::null(); |
| 1535 } | 1541 } |
| 1536 const AbstractType& tp_argument = | 1542 const AbstractType& tp_argument = |
| 1537 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); | 1543 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); |
| 1538 if (!tp_argument.IsType()) { | 1544 if (!tp_argument.IsType()) { |
| 1539 // E.g., it is a TypeParameter. | 1545 // E.g., it is a TypeParameter. |
| 1540 return; | 1546 return SubtypeTestCache::null(); |
| 1541 } | 1547 } |
| 1542 // Malformed type has been caught in the caller chain of this function. | 1548 // Malformed type has been caught in the caller chain of this function. |
| 1543 ASSERT(tp_argument.HasResolvedTypeClass()); | 1549 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 1544 // Check if type argument is dynamic or Object. | 1550 // Check if type argument is dynamic or Object. |
| 1545 const Type& object_type = | 1551 const Type& object_type = |
| 1546 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1552 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1547 Error& malformed_error = Error::Handle(); | 1553 Error& malformed_error = Error::Handle(); |
| 1548 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { | 1554 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 1549 // Instance class test only necessary. | 1555 // Instance class test only necessary. |
| 1550 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1556 return GenerateSubtype1TestCacheLookup( |
| 1551 is_instance_lbl, is_not_instance_lbl); | 1557 node_id, token_index, type_class, is_instance_lbl, is_not_instance_lbl); |
| 1552 return; | |
| 1553 } | 1558 } |
| 1559 const SubtypeTestCache& type_test_cache = |
| 1560 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1554 Label inlined_check, fall_through; | 1561 Label inlined_check, fall_through; |
| 1555 const Immediate raw_null = | 1562 const Immediate raw_null = |
| 1556 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1563 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1557 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1564 __ LoadObject(EDX, type_test_cache); |
| 1558 __ LoadObject(EDX, Array::ZoneHandle( | |
| 1559 Array::New(SubTypeTestCache::kNumEntries))); | |
| 1560 __ pushl(EDX); // Cache array. | 1565 __ pushl(EDX); // Cache array. |
| 1561 __ pushl(EAX); // Instance. | 1566 __ pushl(EAX); // Instance. |
| 1562 __ pushl(raw_null); // Unused. | 1567 __ pushl(raw_null); // Unused. |
| 1563 __ call(&StubCode::Subtype2TestCacheLabel()); | 1568 __ call(&StubCode::Subtype2TestCacheLabel()); |
| 1564 __ popl(EAX); // Discard. | 1569 __ popl(EAX); // Discard. |
| 1565 __ popl(EAX); // Restore receiver. | 1570 __ popl(EAX); // Restore receiver. |
| 1566 __ popl(EDX); // Discard. | 1571 __ popl(EDX); // Discard. |
| 1567 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 1572 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1568 | 1573 |
| 1569 __ cmpl(ECX, raw_null); | 1574 __ cmpl(ECX, raw_null); |
| 1570 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1575 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1571 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1576 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1572 __ CompareObject(ECX, bool_true); | 1577 __ CompareObject(ECX, bool_true); |
| 1573 __ j(EQUAL, is_instance_lbl); | 1578 __ j(EQUAL, is_instance_lbl); |
| 1574 __ jmp(is_not_instance_lbl); | 1579 __ jmp(is_not_instance_lbl); |
| 1575 __ Bind(&fall_through); | 1580 __ Bind(&fall_through); |
| 1581 return type_test_cache.raw(); |
| 1576 } | 1582 } |
| 1577 | 1583 |
| 1578 | 1584 |
| 1579 // EAX: instance to test. | 1585 // EAX: instance to test. |
| 1580 // Clobbers: EBX, ECX, EDX. | 1586 // Clobbers: EBX, ECX, EDX. |
| 1581 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( | 1587 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( |
| 1582 intptr_t node_id, | 1588 intptr_t node_id, |
| 1583 intptr_t token_index, | 1589 intptr_t token_index, |
| 1584 const AbstractType& type, | 1590 const AbstractType& type, |
| 1585 Label* is_instance_lbl, | 1591 Label* is_instance_lbl, |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1825 __ PushObject(dst_name); // Push the name of the destination. | 1831 __ PushObject(dst_name); // Push the name of the destination. |
| 1826 __ PushObject(error_message); | 1832 __ PushObject(error_message); |
| 1827 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | 1833 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1828 // We should never return here. | 1834 // We should never return here. |
| 1829 __ int3(); | 1835 __ int3(); |
| 1830 | 1836 |
| 1831 __ Bind(&done); // For a null object. | 1837 __ Bind(&done); // For a null object. |
| 1832 return; | 1838 return; |
| 1833 } | 1839 } |
| 1834 | 1840 |
| 1835 GenerateInlineInstanceof(node_id, token_index, dst_type, | 1841 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 1836 &done, &runtime_call); | 1842 test_cache = GenerateInlineInstanceof(node_id, token_index, dst_type, |
| 1843 &done, &runtime_call); |
| 1837 | 1844 |
| 1838 __ Bind(&runtime_call); | 1845 __ Bind(&runtime_call); |
| 1839 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1846 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1840 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 1847 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 1841 __ pushl(Immediate(Smi::RawValue(node_id))); // node-id. | 1848 __ pushl(Immediate(Smi::RawValue(node_id))); // node-id. |
| 1842 __ pushl(EAX); // Push the source object. | 1849 __ pushl(EAX); // Push the source object. |
| 1843 __ PushObject(dst_type); // Push the type of the destination. | 1850 __ PushObject(dst_type); // Push the type of the destination. |
| 1844 if (dst_type.IsInstantiated()) { | 1851 if (dst_type.IsInstantiated()) { |
| 1845 __ pushl(raw_null); // Null instantiator. | 1852 __ pushl(raw_null); // Null instantiator. |
| 1846 } else { | 1853 } else { |
| 1847 GenerateInstantiatorTypeArguments(token_index); | 1854 GenerateInstantiatorTypeArguments(token_index); |
| 1848 } | 1855 } |
| 1849 __ PushObject(dst_name); // Push the name of the destination. | 1856 __ PushObject(dst_name); // Push the name of the destination. |
| 1857 __ LoadObject(EAX, test_cache); |
| 1858 __ pushl(EAX); |
| 1850 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); | 1859 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); |
| 1851 // Pop the parameters supplied to the runtime entry. The result of the | 1860 // Pop the parameters supplied to the runtime entry. The result of the |
| 1852 // type check runtime call is the checked value. | 1861 // type check runtime call is the checked value. |
| 1853 __ addl(ESP, Immediate(6 * kWordSize)); | 1862 __ addl(ESP, Immediate(7 * kWordSize)); |
| 1854 __ popl(EAX); | 1863 __ popl(EAX); |
| 1855 | 1864 |
| 1856 // EAX: value. | 1865 // EAX: value. |
| 1857 __ Bind(&done); | 1866 __ Bind(&done); |
| 1858 } | 1867 } |
| 1859 | 1868 |
| 1860 | 1869 |
| 1861 void CodeGenerator::GenerateArgumentTypeChecks() { | 1870 void CodeGenerator::GenerateArgumentTypeChecks() { |
| 1862 const Function& function = parsed_function_.function(); | 1871 const Function& function = parsed_function_.function(); |
| 1863 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); | 1872 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); |
| (...skipping 1128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2992 const Error& error = Error::Handle( | 3001 const Error& error = Error::Handle( |
| 2993 Parser::FormatError(script, token_index, "Error", format, args)); | 3002 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2994 va_end(args); | 3003 va_end(args); |
| 2995 Isolate::Current()->long_jump_base()->Jump(1, error); | 3004 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2996 UNREACHABLE(); | 3005 UNREACHABLE(); |
| 2997 } | 3006 } |
| 2998 | 3007 |
| 2999 } // namespace dart | 3008 } // namespace dart |
| 3000 | 3009 |
| 3001 #endif // defined TARGET_ARCH_IA32 | 3010 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |