| 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 1267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1278 | 1278 |
| 1279 static const Class* CoreClass(const char* c_name) { | 1279 static const Class* CoreClass(const char* c_name) { |
| 1280 const String& class_name = String::Handle(String::NewSymbol(c_name)); | 1280 const String& class_name = String::Handle(String::NewSymbol(c_name)); |
| 1281 const Class& cls = Class::ZoneHandle(Library::Handle( | 1281 const Class& cls = Class::ZoneHandle(Library::Handle( |
| 1282 Library::CoreImplLibrary()).LookupClass(class_name)); | 1282 Library::CoreImplLibrary()).LookupClass(class_name)); |
| 1283 ASSERT(!cls.IsNull()); | 1283 ASSERT(!cls.IsNull()); |
| 1284 return &cls; | 1284 return &cls; |
| 1285 } | 1285 } |
| 1286 | 1286 |
| 1287 | 1287 |
| 1288 // Instance to test is in EAX, test if it is a subtype of type_class. | |
| 1289 // The instance may not be a Smi (test before calling this). | |
| 1290 // The instance may not be NULL (test before calling this). | |
| 1291 // TODO(srdjan): Implement a quicker subtype check, as type test | |
| 1292 // arrays can grow too high, but they may be useful when optimizing | |
| 1293 // code (type-feedback). | |
| 1294 void CodeGenerator::GenerateClassTestCache(intptr_t node_id, | |
| 1295 intptr_t token_index, | |
| 1296 const Class& type_class, | |
| 1297 Label* is_instance_lbl, | |
| 1298 Label* is_not_instance_lbl) { | |
| 1299 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
| 1300 const Immediate raw_null = | |
| 1301 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 1302 Label loop, found_in_cache, runtime_call; | |
| 1303 // Check immediate equality. | |
| 1304 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1305 // ECX: instance class. | |
| 1306 __ CompareObject(ECX, type_class); | |
| 1307 __ j(EQUAL, is_instance_lbl); | |
| 1308 | |
| 1309 // Check immediate superclass equality. | |
| 1310 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | |
| 1311 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | |
| 1312 __ CompareObject(EDI, type_class); | |
| 1313 __ j(EQUAL, is_instance_lbl); | |
| 1314 | |
| 1315 // ECX: instance class. | |
| 1316 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | |
| 1317 __ LoadObject(EDX, Array::ZoneHandle(Array::New(2))); | |
| 1318 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag)); | |
| 1319 __ Bind(&loop); | |
| 1320 __ movl(EBX, Address(EDX, 0)); | |
| 1321 __ cmpl(ECX, EBX); | |
| 1322 __ j(EQUAL, &found_in_cache, Assembler::kNearJump); | |
| 1323 __ addl(EDX, Immediate(kWordSize * 2)); | |
| 1324 __ cmpl(EBX, raw_null); | |
| 1325 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | |
| 1326 __ jmp(&runtime_call, Assembler::kNearJump); | |
| 1327 | |
| 1328 __ Bind(&found_in_cache); | |
| 1329 __ movl(EDX, Address(EDX, kWordSize)); | |
| 1330 __ CompareObject(EDX, bool_true); | |
| 1331 __ j(EQUAL, is_instance_lbl); | |
| 1332 __ jmp(is_not_instance_lbl); | |
| 1333 __ Bind(&runtime_call); | |
| 1334 } | |
| 1335 | |
| 1336 | |
| 1337 // Inline tests according to the 'type' being tested. Jump to labels | 1288 // Inline tests according to the 'type' being tested. Jump to labels |
| 1338 // if we can compute the type-test, otherwise fallthrough. | 1289 // if we can compute the type-test, otherwise fallthrough. |
| 1339 // EAX: instance to be tested. | 1290 // EAX: instance to be tested. |
| 1340 // Clobbers many registers. | 1291 // Clobbers many registers. |
| 1341 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id, | 1292 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id, |
| 1342 intptr_t token_index, | 1293 intptr_t token_index, |
| 1343 const AbstractType& type, | 1294 const AbstractType& type, |
| 1344 Label* is_instance_lbl, | 1295 Label* is_instance_lbl, |
| 1345 Label* is_not_instance_lbl) { | 1296 Label* is_not_instance_lbl) { |
| 1346 if (type.IsInstantiated()) { | 1297 if (type.IsInstantiated()) { |
| 1347 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1298 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1348 // A Smi object cannot be the instance of a parameterized class. | 1299 // A Smi object cannot be the instance of a parameterized class. |
| 1349 // A class equality check is only applicable with a dst type of a | 1300 // A class equality check is only applicable with a dst type of a |
| 1350 // non-parameterized class or with a raw dst type of a parameterized class. | 1301 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1351 if (type_class.HasTypeArguments()) { | 1302 if (type_class.HasTypeArguments()) { |
| 1352 GenerateInstantiatedTypeWithArgumentsTest(node_id, | 1303 GenerateInstantiatedTypeWithArgumentsTest(type, |
| 1353 token_index, | |
| 1354 type, | |
| 1355 is_instance_lbl, | 1304 is_instance_lbl, |
| 1356 is_not_instance_lbl); | 1305 is_not_instance_lbl); |
| 1357 // Fall through to runtime call. | 1306 // Fall through to runtime call. |
| 1358 } else { | 1307 } else { |
| 1359 GenerateInstantiatedTypeNoArgumentsTest(node_id, | 1308 GenerateInstantiatedTypeNoArgumentsTest(node_id, |
| 1360 token_index, | 1309 token_index, |
| 1361 type, | 1310 type, |
| 1362 is_instance_lbl, | 1311 is_instance_lbl, |
| 1363 is_not_instance_lbl); | 1312 is_not_instance_lbl); |
| 1364 // If test non-conclusive so far, try the inlined type-test cache. | 1313 // If test non-conclusive so far, try the inlined type-test cache. |
| 1365 // 'type' is known at compile time. | 1314 // 'type' is known at compile time. |
| 1366 GenerateClassTestCache(node_id, token_index, type_class, | 1315 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1367 is_instance_lbl, is_not_instance_lbl); | 1316 const Immediate raw_null = |
| 1317 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1318 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1319 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); |
| 1320 __ LoadObject(EDX, Array::ZoneHandle(Array::New(2))); |
| 1321 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag)); |
| 1322 Label loop, found_in_cache, runtime_call; |
| 1323 __ Bind(&loop); |
| 1324 __ movl(EBX, Address(EDX, 0)); |
| 1325 __ cmpl(ECX, EBX); |
| 1326 __ j(EQUAL, &found_in_cache, Assembler::kNearJump); |
| 1327 __ addl(EDX, Immediate(kWordSize * 2)); |
| 1328 __ cmpl(EBX, raw_null); |
| 1329 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1330 __ jmp(&runtime_call, Assembler::kNearJump); |
| 1331 |
| 1332 __ Bind(&found_in_cache); |
| 1333 __ movl(EDX, Address(EDX, kWordSize)); |
| 1334 __ CompareObject(EDX, bool_true); |
| 1335 __ j(EQUAL, is_instance_lbl); |
| 1336 __ jmp(is_not_instance_lbl); |
| 1337 __ Bind(&runtime_call); |
| 1368 } | 1338 } |
| 1369 } else { | 1339 } else { |
| 1370 GenerateUninstantiatedTypeTest(type, | 1340 GenerateUninstantiatedTypeTest(type, |
| 1371 token_index, | 1341 token_index, |
| 1372 is_instance_lbl); | 1342 is_instance_lbl); |
| 1373 } | 1343 } |
| 1374 } | 1344 } |
| 1375 | 1345 |
| 1376 | 1346 |
| 1377 // If instanceof type test cannot be performed successfully at compile time and | 1347 // If instanceof type test cannot be performed successfully at compile time and |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1490 __ Bind(&done); | 1460 __ Bind(&done); |
| 1491 } | 1461 } |
| 1492 | 1462 |
| 1493 | 1463 |
| 1494 // EAX: instance to test. | 1464 // EAX: instance to test. |
| 1495 // Clobbers: ECX. | 1465 // Clobbers: ECX. |
| 1496 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 1466 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 1497 // type test is conclusive, otherwise fallthrough if a type test could not | 1467 // type test is conclusive, otherwise fallthrough if a type test could not |
| 1498 // be completed. | 1468 // be completed. |
| 1499 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( | 1469 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( |
| 1500 intptr_t node_id, | |
| 1501 intptr_t token_index, | |
| 1502 const AbstractType& type, | 1470 const AbstractType& type, |
| 1503 Label* is_instance_lbl, | 1471 Label* is_instance_lbl, |
| 1504 Label* is_not_instance_lbl) { | 1472 Label* is_not_instance_lbl) { |
| 1505 ASSERT(type.IsInstantiated()); | 1473 ASSERT(type.IsInstantiated()); |
| 1506 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1474 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1507 ASSERT(type_class.HasTypeArguments()); | 1475 ASSERT(type_class.HasTypeArguments()); |
| 1508 // A Smi object cannot be the instance of a parameterized class. | 1476 // A Smi object cannot be the instance of a parameterized class. |
| 1509 // A class equality check is only applicable with a dst type of a | 1477 // A class equality check is only applicable with a dst type of a |
| 1510 // non-parameterized class or with a raw dst type of a parameterized class. | 1478 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1511 __ testl(EAX, Immediate(kSmiTagMask)); | 1479 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1512 __ j(ZERO, is_not_instance_lbl); | 1480 __ j(ZERO, is_not_instance_lbl); |
| 1513 const AbstractTypeArguments& type_arguments = | 1481 const AbstractTypeArguments& type_arguments = |
| 1514 AbstractTypeArguments::Handle(type.arguments()); | 1482 AbstractTypeArguments::Handle(type.arguments()); |
| 1515 const bool is_raw_type = type_arguments.IsNull() || | 1483 const bool is_raw_type = type_arguments.IsNull() || |
| 1516 type_arguments.IsRaw(type_arguments.Length()); | 1484 type_arguments.IsRaw(type_arguments.Length()); |
| 1517 if (is_raw_type) { | 1485 if (is_raw_type) { |
| 1518 // Dynamic type argument, check only classes. | 1486 // Dynamic type argument, check only classes. |
| 1519 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1487 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1520 if (type.IsListInterface()) { | 1488 if (type.IsListInterface()) { |
| 1521 // TODO(srdjan) also accept List<Object>. | 1489 // TODO(srdjan) also accept List<Object>. |
| 1522 __ CompareObject(ECX, *CoreClass("ObjectArray")); | 1490 __ CompareObject(ECX, *CoreClass("ObjectArray")); |
| 1523 __ j(EQUAL, is_instance_lbl); | 1491 __ j(EQUAL, is_instance_lbl); |
| 1524 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | 1492 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); |
| 1525 __ j(EQUAL, is_instance_lbl); | 1493 __ j(EQUAL, is_instance_lbl); |
| 1494 } else if (!type_class.is_interface()) { |
| 1495 __ CompareObject(ECX, type_class); |
| 1496 __ j(EQUAL, is_instance_lbl); |
| 1526 } | 1497 } |
| 1527 GenerateClassTestCache(node_id, token_index, type_class, | 1498 } else { |
| 1528 is_instance_lbl, is_not_instance_lbl); | 1499 // TODO(srdjan): do type test on type arguments. |
| 1529 } | 1500 } |
| 1530 // TODO(srdjan): do type test on type arguments. | |
| 1531 // Fall through if type test is not conclusive | 1501 // Fall through if type test is not conclusive |
| 1532 } | 1502 } |
| 1533 | 1503 |
| 1534 | 1504 |
| 1535 // EAX: instance to test. | 1505 // EAX: instance to test. |
| 1536 // Clobbers: EBX, ECX, EDX. | 1506 // Clobbers: EBX, ECX, EDX. |
| 1537 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( | 1507 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( |
| 1538 intptr_t node_id, | 1508 intptr_t node_id, |
| 1539 intptr_t token_index, | 1509 intptr_t token_index, |
| 1540 const AbstractType& type, | 1510 const AbstractType& type, |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1677 // InstantiatedType. It is therefore necessary to check its class. | 1647 // InstantiatedType. It is therefore necessary to check its class. |
| 1678 __ movl(ECX, FieldAddress(EDX, Object::class_offset())); | 1648 __ movl(ECX, FieldAddress(EDX, Object::class_offset())); |
| 1679 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class())); | 1649 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class())); |
| 1680 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1650 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1681 | 1651 |
| 1682 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset())); | 1652 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset())); |
| 1683 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset())); | 1653 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset())); |
| 1684 // Check that class of type has no type parameters. | 1654 // Check that class of type has no type parameters. |
| 1685 __ cmpl(ECX, raw_null); | 1655 __ cmpl(ECX, raw_null); |
| 1686 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1656 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1687 // EAX has non-parameterized class. | |
| 1688 // Check class equality | |
| 1689 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1690 __ movl(ECX, FieldAddress(ECX, Type::Type::type_class_offset())); | |
| 1691 __ cmpl(ECX, EDX); | |
| 1692 __ j(EQUAL, is_instance_lbl); | |
| 1693 | |
| 1694 // We have a non-parameterized class in EDX, compare with class of | 1657 // We have a non-parameterized class in EDX, compare with class of |
| 1695 // value in EAX. EAX, EDX are preserved in stub. | 1658 // value in EAX. EAX, EDX are preserved in stub. |
| 1696 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1697 __ call(&StubCode::IsRawSubTypeLabel()); | 1659 __ call(&StubCode::IsRawSubTypeLabel()); |
| 1698 // Result in EBX: 1 is raw subtype. | 1660 // Result in EBX: 1 is raw subtype. |
| 1699 __ cmpl(EBX, Immediate(1)); | 1661 __ cmpl(EBX, Immediate(1)); |
| 1700 __ j(EQUAL, is_instance_lbl); | 1662 __ j(EQUAL, is_instance_lbl); |
| 1701 | 1663 |
| 1702 // Test not conclusive. | 1664 // Test not conclusive. |
| 1703 __ Bind(&fall_through); | 1665 __ Bind(&fall_through); |
| 1704 } | 1666 } |
| 1705 } | 1667 } |
| 1706 | 1668 |
| (...skipping 1212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2919 const Error& error = Error::Handle( | 2881 const Error& error = Error::Handle( |
| 2920 Parser::FormatError(script, token_index, "Error", format, args)); | 2882 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2921 va_end(args); | 2883 va_end(args); |
| 2922 Isolate::Current()->long_jump_base()->Jump(1, error); | 2884 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2923 UNREACHABLE(); | 2885 UNREACHABLE(); |
| 2924 } | 2886 } |
| 2925 | 2887 |
| 2926 } // namespace dart | 2888 } // namespace dart |
| 2927 | 2889 |
| 2928 #endif // defined TARGET_ARCH_IA32 | 2890 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |