| 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 1188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1199 operator_name, | 1199 operator_name, |
| 1200 kNumberOfArguments, | 1200 kNumberOfArguments, |
| 1201 kNoArgumentNames, | 1201 kNoArgumentNames, |
| 1202 kNumArgumentsChecked); | 1202 kNumArgumentsChecked); |
| 1203 if (IsResultNeeded(node)) { | 1203 if (IsResultNeeded(node)) { |
| 1204 __ pushl(EAX); | 1204 __ pushl(EAX); |
| 1205 } | 1205 } |
| 1206 } | 1206 } |
| 1207 | 1207 |
| 1208 | 1208 |
| 1209 static const Class* CoreClass(const char* c_name) { | |
| 1210 const String& class_name = String::Handle(String::NewSymbol(c_name)); | |
| 1211 const Class& cls = Class::ZoneHandle(Library::Handle( | |
| 1212 Library::CoreImplLibrary()).LookupClass(class_name)); | |
| 1213 ASSERT(!cls.IsNull()); | |
| 1214 return &cls; | |
| 1215 } | |
| 1216 | |
| 1217 | |
| 1218 // Instance to test is in EAX. Test if its class is in subtype test cache array | 1209 // Instance to test is in EAX. Test if its class is in subtype test cache array |
| 1219 // and use the result in the array to jump to one of the labels. Fall through | 1210 // and use the result in the array to jump to one of the labels. Fall through |
| 1220 // if the instance is not in the cache array. | 1211 // if the instance is not in the cache array. |
| 1221 // TODO(srdjan): Implement a quicker subtype check, as type test | 1212 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 1222 // arrays can grow too high, but they may be useful when optimizing | 1213 // arrays can grow too high, but they may be useful when optimizing |
| 1223 // code (type-feedback). | 1214 // code (type-feedback). |
| 1224 RawSubtypeTestCache* CodeGenerator::GenerateSubtype1TestCacheLookup( | 1215 RawSubtypeTestCache* CodeGenerator::GenerateSubtype1TestCacheLookup( |
| 1225 intptr_t node_id, | 1216 intptr_t node_id, |
| 1226 intptr_t token_index, | 1217 intptr_t token_index, |
| 1227 const Class& type_class, | 1218 const Class& type_class, |
| 1228 Label* is_instance_lbl, | 1219 Label* is_instance_lbl, |
| 1229 Label* is_not_instance_lbl) { | 1220 Label* is_not_instance_lbl) { |
| 1230 const SubtypeTestCache& type_test_cache = | 1221 const SubtypeTestCache& type_test_cache = |
| 1231 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 1222 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1232 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1223 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1233 const Immediate raw_null = | 1224 const Immediate raw_null = |
| 1234 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1225 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1235 // Check immediate equality. | 1226 // Check immediate equality. |
| 1236 __ LoadClassOfObject(ECX, EAX, EDI); | 1227 __ LoadClass(ECX, EAX, EDI); |
| 1237 // ECX: instance class. | 1228 // ECX: instance class. |
| 1238 __ CompareObject(ECX, type_class); | 1229 __ CompareObject(ECX, type_class); |
| 1239 __ j(EQUAL, is_instance_lbl); | 1230 __ j(EQUAL, is_instance_lbl); |
| 1240 | 1231 |
| 1241 // Check immediate superclass equality. | 1232 // Check immediate superclass equality. |
| 1242 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 1233 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 1243 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 1234 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 1244 __ CompareObject(EDI, type_class); | 1235 __ CompareObject(EDI, type_class); |
| 1245 __ j(EQUAL, is_instance_lbl); | 1236 __ j(EQUAL, is_instance_lbl); |
| 1246 | 1237 |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1447 // A class equality check is only applicable with a dst type of a | 1438 // A class equality check is only applicable with a dst type of a |
| 1448 // non-parameterized class or with a raw dst type of a parameterized class. | 1439 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1449 __ testl(EAX, Immediate(kSmiTagMask)); | 1440 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1450 __ j(ZERO, is_not_instance_lbl); | 1441 __ j(ZERO, is_not_instance_lbl); |
| 1451 const AbstractTypeArguments& type_arguments = | 1442 const AbstractTypeArguments& type_arguments = |
| 1452 AbstractTypeArguments::ZoneHandle(type.arguments()); | 1443 AbstractTypeArguments::ZoneHandle(type.arguments()); |
| 1453 const bool is_raw_type = type_arguments.IsNull() || | 1444 const bool is_raw_type = type_arguments.IsNull() || |
| 1454 type_arguments.IsRaw(type_arguments.Length()); | 1445 type_arguments.IsRaw(type_arguments.Length()); |
| 1455 if (is_raw_type) { | 1446 if (is_raw_type) { |
| 1456 // Dynamic type argument, check only classes. | 1447 // Dynamic type argument, check only classes. |
| 1457 __ LoadClassIndexOfObject(ECX, EAX); | 1448 __ LoadClassId(ECX, EAX); |
| 1458 if (!type_class.is_interface()) { | 1449 if (!type_class.is_interface()) { |
| 1459 __ cmpl(ECX, Immediate(type_class.index())); | 1450 __ cmpl(ECX, Immediate(type_class.index())); |
| 1460 __ j(EQUAL, is_instance_lbl); | 1451 __ j(EQUAL, is_instance_lbl); |
| 1461 } | 1452 } |
| 1462 if (type.IsListInterface()) { | 1453 if (type.IsListInterface()) { |
| 1463 // TODO(srdjan) also accept List<Object>. | 1454 // TODO(srdjan) also accept List<Object>. |
| 1464 __ cmpl(ECX, Immediate(CoreClass("ObjectArray")->index())); | 1455 __ cmpl(ECX, Immediate(kArray)); |
| 1465 __ j(EQUAL, is_instance_lbl); | 1456 __ j(EQUAL, is_instance_lbl); |
| 1466 __ cmpl(ECX, Immediate(CoreClass("GrowableObjectArray")->index())); | 1457 __ cmpl(ECX, Immediate(kGrowableObjectArray)); |
| 1467 __ j(EQUAL, is_instance_lbl); | 1458 __ j(EQUAL, is_instance_lbl); |
| 1468 } | 1459 } |
| 1469 return | 1460 return |
| 1470 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1461 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1471 is_instance_lbl, is_not_instance_lbl); | 1462 is_instance_lbl, is_not_instance_lbl); |
| 1472 } | 1463 } |
| 1473 // If one type argument only, quick check. | 1464 // If one type argument only, quick check. |
| 1474 if (type_arguments.Length() == 1) { | 1465 if (type_arguments.Length() == 1) { |
| 1475 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 1466 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 1476 type_arguments.TypeAt(0)); | 1467 type_arguments.TypeAt(0)); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1545 } else { | 1536 } else { |
| 1546 __ jmp(is_not_instance_lbl); | 1537 __ jmp(is_not_instance_lbl); |
| 1547 } | 1538 } |
| 1548 // Compare if the classes are equal. | 1539 // Compare if the classes are equal. |
| 1549 __ Bind(&compare_classes); | 1540 __ Bind(&compare_classes); |
| 1550 | 1541 |
| 1551 // Checking against interface. | 1542 // Checking against interface. |
| 1552 // However, for specific core library interfaces, we can check for | 1543 // However, for specific core library interfaces, we can check for |
| 1553 // specific core library classes. | 1544 // specific core library classes. |
| 1554 if (type.IsBoolInterface()) { | 1545 if (type.IsBoolInterface()) { |
| 1555 const Class& bool_class = Class::Handle( | 1546 __ CompareClassId(EAX, kBool, ECX); |
| 1556 Isolate::Current()->object_store()->bool_class()); | |
| 1557 __ CompareClassOfObject(EAX, bool_class, ECX); | |
| 1558 __ j(EQUAL, is_instance_lbl); | 1547 __ j(EQUAL, is_instance_lbl); |
| 1559 __ jmp(is_not_instance_lbl); | 1548 __ jmp(is_not_instance_lbl); |
| 1560 return; | 1549 return; |
| 1561 } | 1550 } |
| 1562 // If type is an interface, we can skip the class equality check, | 1551 // If type is an interface, we can skip the class equality check, |
| 1563 // because instances cannot be of an interface type. | 1552 // because instances cannot be of an interface type. |
| 1564 if (!type_class.is_interface()) { | 1553 if (!type_class.is_interface()) { |
| 1565 __ CompareClassOfObject(EAX, type_class, ECX); | 1554 __ CompareClassId(EAX, type_class.index(), ECX); |
| 1566 __ j(EQUAL, is_instance_lbl); | 1555 __ j(EQUAL, is_instance_lbl); |
| 1567 } | 1556 } |
| 1568 if (type.IsSubtypeOf( | 1557 if (type.IsSubtypeOf( |
| 1569 Type::Handle(Type::NumberInterface()), &malformed_error)) { | 1558 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1570 // Custom checking for numbers (Smi, Mint, Bigint and Double) | 1559 // Custom checking for numbers (Smi, Mint, Bigint and Double) |
| 1571 __ LoadClassIndexOfObject(ECX, EAX); | 1560 __ LoadClassId(ECX, EAX); |
| 1572 | 1561 |
| 1573 if (type.IsIntInterface() || type.IsNumberInterface()) { | 1562 if (type.IsIntInterface() || type.IsNumberInterface()) { |
| 1574 // We already checked for Smi above. | 1563 // We already checked for Smi above. |
| 1575 __ cmpl(ECX, Immediate(kMint)); | 1564 __ cmpl(ECX, Immediate(kMint)); |
| 1576 __ j(EQUAL, is_instance_lbl); | 1565 __ j(EQUAL, is_instance_lbl); |
| 1577 __ cmpl(ECX, Immediate(kBigint)); | 1566 __ cmpl(ECX, Immediate(kBigint)); |
| 1578 __ j(EQUAL, is_instance_lbl); | 1567 __ j(EQUAL, is_instance_lbl); |
| 1579 if (type.IsIntInterface()) { | 1568 if (type.IsIntInterface()) { |
| 1580 __ jmp(is_not_instance_lbl); | 1569 __ jmp(is_not_instance_lbl); |
| 1581 } | 1570 } |
| 1582 } | 1571 } |
| 1583 if (type.IsDoubleInterface() || type.IsNumberInterface()) { | 1572 if (type.IsDoubleInterface() || type.IsNumberInterface()) { |
| 1584 __ cmpl(ECX, Immediate(kDouble)); | 1573 __ cmpl(ECX, Immediate(kDouble)); |
| 1585 __ j(EQUAL, is_instance_lbl); | 1574 __ j(EQUAL, is_instance_lbl); |
| 1586 __ jmp(is_not_instance_lbl); | 1575 __ jmp(is_not_instance_lbl); |
| 1587 } | 1576 } |
| 1588 } else if (type.IsStringInterface()) { | 1577 } else if (type.IsStringInterface()) { |
| 1589 __ LoadClassIndexOfObject(ECX, EAX); | 1578 __ LoadClassId(ECX, EAX); |
| 1590 __ cmpl(ECX, Immediate(kOneByteString)); | 1579 __ cmpl(ECX, Immediate(kOneByteString)); |
| 1591 __ j(EQUAL, is_instance_lbl); | 1580 __ j(EQUAL, is_instance_lbl); |
| 1592 __ cmpl(ECX, Immediate(kTwoByteString)); | 1581 __ cmpl(ECX, Immediate(kTwoByteString)); |
| 1593 __ j(EQUAL, is_instance_lbl); | 1582 __ j(EQUAL, is_instance_lbl); |
| 1594 __ cmpl(ECX, Immediate(kFourByteString)); | 1583 __ cmpl(ECX, Immediate(kFourByteString)); |
| 1595 __ j(EQUAL, is_instance_lbl); | 1584 __ j(EQUAL, is_instance_lbl); |
| 1596 } else if (type.IsFunctionInterface()) { | 1585 } else if (type.IsFunctionInterface()) { |
| 1597 // Check if instance is a closure. | 1586 // Check if instance is a closure. |
| 1598 const Immediate raw_null = | 1587 const Immediate raw_null = |
| 1599 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1588 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1600 __ LoadClassOfObject(ECX, EAX, EBX); | 1589 __ LoadClass(ECX, EAX, EBX); |
| 1601 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset())); | 1590 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset())); |
| 1602 __ cmpl(ECX, raw_null); | 1591 __ cmpl(ECX, raw_null); |
| 1603 __ j(NOT_EQUAL, is_instance_lbl); | 1592 __ j(NOT_EQUAL, is_instance_lbl); |
| 1604 } | 1593 } |
| 1605 // Otherwise fallthrough. | 1594 // Otherwise fallthrough. |
| 1606 } | 1595 } |
| 1607 | 1596 |
| 1608 | 1597 |
| 1609 // EAX: instance to test. | 1598 // EAX: instance to test. |
| 1610 // Clobbers: EBX, EDX, ECX. | 1599 // Clobbers: EBX, EDX, ECX. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1626 // Type arguments are on stack. | 1615 // Type arguments are on stack. |
| 1627 __ popl(EBX); | 1616 __ popl(EBX); |
| 1628 // Check if type argument is dynamic. | 1617 // Check if type argument is dynamic. |
| 1629 __ cmpl(EBX, raw_null); | 1618 __ cmpl(EBX, raw_null); |
| 1630 __ j(EQUAL, is_instance_lbl); | 1619 __ j(EQUAL, is_instance_lbl); |
| 1631 | 1620 |
| 1632 // EBX: instantiator type arguments. | 1621 // EBX: instantiator type arguments. |
| 1633 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. | 1622 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. |
| 1634 // We expect that frequently checked objects wull have their type arguments | 1623 // We expect that frequently checked objects wull have their type arguments |
| 1635 // converted into instance of TypeArguments. | 1624 // converted into instance of TypeArguments. |
| 1636 __ CompareClassOfObject(EBX, | 1625 __ CompareClassId(EBX, kTypeArguments, EDX); |
| 1637 Class::Handle(Object::type_arguments_class()), | |
| 1638 EDX); | |
| 1639 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1626 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1640 | 1627 |
| 1641 __ movl(EDX, | 1628 __ movl(EDX, |
| 1642 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); | 1629 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); |
| 1643 // EDX: concrete type of type. | 1630 // EDX: concrete type of type. |
| 1644 // Check if type argument is dynamic. | 1631 // Check if type argument is dynamic. |
| 1645 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); | 1632 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); |
| 1646 __ j(EQUAL, is_instance_lbl); | 1633 __ j(EQUAL, is_instance_lbl); |
| 1647 __ cmpl(EDX, raw_null); | 1634 __ cmpl(EDX, raw_null); |
| 1648 __ j(EQUAL, is_instance_lbl); | 1635 __ j(EQUAL, is_instance_lbl); |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1859 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1846 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1860 Label runtime_call, done; | 1847 Label runtime_call, done; |
| 1861 __ movl(EAX, Address(ESP, 0)); | 1848 __ movl(EAX, Address(ESP, 0)); |
| 1862 __ cmpl(EAX, raw_null); | 1849 __ cmpl(EAX, raw_null); |
| 1863 __ j(EQUAL, &runtime_call, Assembler::kNearJump); | 1850 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 1864 __ testl(EAX, Immediate(kSmiTagMask)); | 1851 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1865 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi. | 1852 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi. |
| 1866 // This check should pass if the receiver's class implements the interface | 1853 // This check should pass if the receiver's class implements the interface |
| 1867 // 'bool'. Check only class 'Bool' since it is the only legal implementation | 1854 // 'bool'. Check only class 'Bool' since it is the only legal implementation |
| 1868 // of the interface 'bool'. | 1855 // of the interface 'bool'. |
| 1869 const Class& bool_class = | 1856 __ CompareClassId(EAX, kBool, ECX); |
| 1870 Class::Handle(Isolate::Current()->object_store()->bool_class()); | |
| 1871 __ CompareClassOfObject(EAX, bool_class, ECX); | |
| 1872 __ j(EQUAL, &done, Assembler::kNearJump); | 1857 __ j(EQUAL, &done, Assembler::kNearJump); |
| 1873 | 1858 |
| 1874 __ Bind(&runtime_call); | 1859 __ Bind(&runtime_call); |
| 1875 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 1860 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 1876 __ pushl(EAX); // Push the source object. | 1861 __ pushl(EAX); // Push the source object. |
| 1877 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); | 1862 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); |
| 1878 // We should never return here. | 1863 // We should never return here. |
| 1879 __ int3(); | 1864 __ int3(); |
| 1880 | 1865 |
| 1881 __ Bind(&done); | 1866 __ Bind(&done); |
| (...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2503 __ cmpl(EAX, raw_null); | 2488 __ cmpl(EAX, raw_null); |
| 2504 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 2489 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 2505 } | 2490 } |
| 2506 // Instantiate non-null type arguments. | 2491 // Instantiate non-null type arguments. |
| 2507 if (type_arguments.IsUninstantiatedIdentity()) { | 2492 if (type_arguments.IsUninstantiatedIdentity()) { |
| 2508 // Check if the instantiator type argument vector is a TypeArguments of a | 2493 // Check if the instantiator type argument vector is a TypeArguments of a |
| 2509 // matching length and, if so, use it as the instantiated type_arguments. | 2494 // matching length and, if so, use it as the instantiated type_arguments. |
| 2510 // No need to check RAX for null (again), because a null instance will | 2495 // No need to check RAX for null (again), because a null instance will |
| 2511 // have the wrong class (Null instead of TypeArguments). | 2496 // have the wrong class (Null instead of TypeArguments). |
| 2512 Label type_arguments_uninstantiated; | 2497 Label type_arguments_uninstantiated; |
| 2513 __ CompareClassOfObject(EAX, | 2498 __ CompareClassId(EAX, kTypeArguments, ECX); |
| 2514 Class::Handle(Object::type_arguments_class()), | |
| 2515 ECX); | |
| 2516 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); | 2499 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); |
| 2517 __ cmpl(FieldAddress(EAX, TypeArguments::length_offset()), | 2500 __ cmpl(FieldAddress(EAX, TypeArguments::length_offset()), |
| 2518 Immediate(Smi::RawValue(len))); | 2501 Immediate(Smi::RawValue(len))); |
| 2519 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 2502 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 2520 __ Bind(&type_arguments_uninstantiated); | 2503 __ Bind(&type_arguments_uninstantiated); |
| 2521 } | 2504 } |
| 2522 if (instantiate_type_arguments) { | 2505 if (instantiate_type_arguments) { |
| 2523 // A runtime call to instantiate the type arguments is required. | 2506 // A runtime call to instantiate the type arguments is required. |
| 2524 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 2507 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 2525 __ PushObject(type_arguments); | 2508 __ PushObject(type_arguments); |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2971 const Error& error = Error::Handle( | 2954 const Error& error = Error::Handle( |
| 2972 Parser::FormatError(script, token_index, "Error", format, args)); | 2955 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2973 va_end(args); | 2956 va_end(args); |
| 2974 Isolate::Current()->long_jump_base()->Jump(1, error); | 2957 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2975 UNREACHABLE(); | 2958 UNREACHABLE(); |
| 2976 } | 2959 } |
| 2977 | 2960 |
| 2978 } // namespace dart | 2961 } // namespace dart |
| 2979 | 2962 |
| 2980 #endif // defined TARGET_ARCH_IA32 | 2963 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |