| 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 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1226 intptr_t token_index, | 1226 intptr_t token_index, |
| 1227 const Class& type_class, | 1227 const Class& type_class, |
| 1228 Label* is_instance_lbl, | 1228 Label* is_instance_lbl, |
| 1229 Label* is_not_instance_lbl) { | 1229 Label* is_not_instance_lbl) { |
| 1230 const SubtypeTestCache& type_test_cache = | 1230 const SubtypeTestCache& type_test_cache = |
| 1231 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 1231 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1232 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1232 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1233 const Immediate raw_null = | 1233 const Immediate raw_null = |
| 1234 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1234 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1235 // Check immediate equality. | 1235 // Check immediate equality. |
| 1236 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1236 __ GetClassOf(ECX, EAX, EDI); |
| 1237 // ECX: instance class. | 1237 // ECX: instance class. |
| 1238 __ CompareObject(ECX, type_class); | 1238 __ CompareObject(ECX, type_class); |
| 1239 __ j(EQUAL, is_instance_lbl); | 1239 __ j(EQUAL, is_instance_lbl); |
| 1240 | 1240 |
| 1241 // Check immediate superclass equality. | 1241 // Check immediate superclass equality. |
| 1242 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 1242 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 1243 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 1243 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 1244 __ CompareObject(EDI, type_class); | 1244 __ CompareObject(EDI, type_class); |
| 1245 __ j(EQUAL, is_instance_lbl); | 1245 __ j(EQUAL, is_instance_lbl); |
| 1246 | 1246 |
| (...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 | 1447 // 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. | 1448 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1449 __ testl(EAX, Immediate(kSmiTagMask)); | 1449 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1450 __ j(ZERO, is_not_instance_lbl); | 1450 __ j(ZERO, is_not_instance_lbl); |
| 1451 const AbstractTypeArguments& type_arguments = | 1451 const AbstractTypeArguments& type_arguments = |
| 1452 AbstractTypeArguments::ZoneHandle(type.arguments()); | 1452 AbstractTypeArguments::ZoneHandle(type.arguments()); |
| 1453 const bool is_raw_type = type_arguments.IsNull() || | 1453 const bool is_raw_type = type_arguments.IsNull() || |
| 1454 type_arguments.IsRaw(type_arguments.Length()); | 1454 type_arguments.IsRaw(type_arguments.Length()); |
| 1455 if (is_raw_type) { | 1455 if (is_raw_type) { |
| 1456 // Dynamic type argument, check only classes. | 1456 // Dynamic type argument, check only classes. |
| 1457 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1457 __ LoadObjectClassId(ECX, EAX); |
| 1458 if (!type_class.is_interface()) { | 1458 if (!type_class.is_interface()) { |
| 1459 __ CompareObject(ECX, type_class); | 1459 __ cmpl(ECX, Immediate(type_class.index())); |
| 1460 __ j(EQUAL, is_instance_lbl); | 1460 __ j(EQUAL, is_instance_lbl); |
| 1461 } | 1461 } |
| 1462 if (type.IsListInterface()) { | 1462 if (type.IsListInterface()) { |
| 1463 // TODO(srdjan) also accept List<Object>. | 1463 // TODO(srdjan) also accept List<Object>. |
| 1464 __ CompareObject(ECX, *CoreClass("ObjectArray")); | 1464 __ cmpl(ECX, Immediate(CoreClass("ObjectArray")->index())); |
| 1465 __ j(EQUAL, is_instance_lbl); | 1465 __ j(EQUAL, is_instance_lbl); |
| 1466 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | 1466 __ cmpl(ECX, Immediate(CoreClass("GrowableObjectArray")->index())); |
| 1467 __ j(EQUAL, is_instance_lbl); | 1467 __ j(EQUAL, is_instance_lbl); |
| 1468 } | 1468 } |
| 1469 return | 1469 return |
| 1470 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1470 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1471 is_instance_lbl, is_not_instance_lbl); | 1471 is_instance_lbl, is_not_instance_lbl); |
| 1472 } | 1472 } |
| 1473 // If one type argument only, quick check. | 1473 // If one type argument only, quick check. |
| 1474 if (type_arguments.Length() == 1) { | 1474 if (type_arguments.Length() == 1) { |
| 1475 const AbstractType& tp_argument = AbstractType::ZoneHandle( | 1475 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 1476 type_arguments.TypeAt(0)); | 1476 type_arguments.TypeAt(0)); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1545 } else { | 1545 } else { |
| 1546 __ jmp(is_not_instance_lbl); | 1546 __ jmp(is_not_instance_lbl); |
| 1547 } | 1547 } |
| 1548 // Compare if the classes are equal. | 1548 // Compare if the classes are equal. |
| 1549 __ Bind(&compare_classes); | 1549 __ Bind(&compare_classes); |
| 1550 | 1550 |
| 1551 // Checking against interface. | 1551 // Checking against interface. |
| 1552 // However, for specific core library interfaces, we can check for | 1552 // However, for specific core library interfaces, we can check for |
| 1553 // specific core library classes. | 1553 // specific core library classes. |
| 1554 if (type.IsBoolInterface()) { | 1554 if (type.IsBoolInterface()) { |
| 1555 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1555 const Class& bool_class = Class::Handle( |
| 1556 const Class& bool_class = Class::ZoneHandle( | |
| 1557 Isolate::Current()->object_store()->bool_class()); | 1556 Isolate::Current()->object_store()->bool_class()); |
| 1558 __ CompareObject(ECX, bool_class); | 1557 __ CompareClassOf(EAX, bool_class, ECX); |
| 1559 __ j(EQUAL, is_instance_lbl); | 1558 __ j(EQUAL, is_instance_lbl); |
| 1560 __ jmp(is_not_instance_lbl); | 1559 __ jmp(is_not_instance_lbl); |
| 1561 return; | 1560 return; |
| 1562 } | 1561 } |
| 1563 // If type is an interface, we can skip the class equality check, | 1562 // If type is an interface, we can skip the class equality check, |
| 1564 // because instances cannot be of an interface type. | 1563 // because instances cannot be of an interface type. |
| 1565 if (!type_class.is_interface()) { | 1564 if (!type_class.is_interface()) { |
| 1566 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1565 __ CompareClassOf(EAX, type_class, ECX); |
| 1567 __ CompareObject(ECX, type_class); | |
| 1568 __ j(EQUAL, is_instance_lbl); | 1566 __ j(EQUAL, is_instance_lbl); |
| 1569 } | 1567 } |
| 1570 if (type.IsSubtypeOf( | 1568 if (type.IsSubtypeOf( |
| 1571 Type::Handle(Type::NumberInterface()), &malformed_error)) { | 1569 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1572 // Custom checking for numbers (Smi, Mint, Bigint and Double) | 1570 // Custom checking for numbers (Smi, Mint, Bigint and Double) |
| 1573 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1571 __ LoadObjectClassId(ECX, EAX); |
| 1572 |
| 1574 if (type.IsIntInterface() || type.IsNumberInterface()) { | 1573 if (type.IsIntInterface() || type.IsNumberInterface()) { |
| 1575 // We already checked for Smi above. | 1574 // We already checked for Smi above. |
| 1576 const Class& mint_class = Class::ZoneHandle( | 1575 const Class& mint_class = Class::ZoneHandle( |
| 1577 Isolate::Current()->object_store()->mint_class()); | 1576 Isolate::Current()->object_store()->mint_class()); |
| 1578 const Class& bigint_class = Class::ZoneHandle( | 1577 const Class& bigint_class = Class::ZoneHandle( |
| 1579 Isolate::Current()->object_store()->bigint_class()); | 1578 Isolate::Current()->object_store()->bigint_class()); |
| 1580 __ CompareObject(ECX, mint_class); | 1579 __ CompareClassId(ECX, mint_class); |
| 1581 __ j(EQUAL, is_instance_lbl); | 1580 __ j(EQUAL, is_instance_lbl); |
| 1582 __ CompareObject(ECX, bigint_class); | 1581 __ CompareClassId(ECX, bigint_class); |
| 1583 __ j(EQUAL, is_instance_lbl); | 1582 __ j(EQUAL, is_instance_lbl); |
| 1584 if (type.IsIntInterface()) { | 1583 if (type.IsIntInterface()) { |
| 1585 __ jmp(is_not_instance_lbl); | 1584 __ jmp(is_not_instance_lbl); |
| 1586 } | 1585 } |
| 1587 } | 1586 } |
| 1588 if (type.IsDoubleInterface() || type.IsNumberInterface()) { | 1587 if (type.IsDoubleInterface() || type.IsNumberInterface()) { |
| 1589 const Class& double_class = Class::ZoneHandle( | 1588 const Class& double_class = Class::ZoneHandle( |
| 1590 Isolate::Current()->object_store()->double_class()); | 1589 Isolate::Current()->object_store()->double_class()); |
| 1591 __ CompareObject(ECX, double_class); | 1590 __ CompareClassId(ECX, double_class); |
| 1592 __ j(EQUAL, is_instance_lbl); | 1591 __ j(EQUAL, is_instance_lbl); |
| 1593 __ jmp(is_not_instance_lbl); | 1592 __ jmp(is_not_instance_lbl); |
| 1594 } | 1593 } |
| 1595 } else if (type.IsStringInterface()) { | 1594 } else if (type.IsStringInterface()) { |
| 1596 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1595 __ LoadObjectClassId(ECX, EAX); |
| 1597 const Class& one_byte_string_class = Class::ZoneHandle( | 1596 const Class& one_byte_string_class = Class::ZoneHandle( |
| 1598 Isolate::Current()->object_store()->one_byte_string_class()); | 1597 Isolate::Current()->object_store()->one_byte_string_class()); |
| 1599 const Class& two_byte_string_class = Class::ZoneHandle( | 1598 const Class& two_byte_string_class = Class::ZoneHandle( |
| 1600 Isolate::Current()->object_store()->two_byte_string_class()); | 1599 Isolate::Current()->object_store()->two_byte_string_class()); |
| 1601 const Class& four_byte_string_class = Class::ZoneHandle( | 1600 const Class& four_byte_string_class = Class::ZoneHandle( |
| 1602 Isolate::Current()->object_store()->four_byte_string_class()); | 1601 Isolate::Current()->object_store()->four_byte_string_class()); |
| 1603 __ CompareObject(ECX, one_byte_string_class); | 1602 __ CompareClassId(ECX, one_byte_string_class); |
| 1604 __ j(EQUAL, is_instance_lbl); | 1603 __ j(EQUAL, is_instance_lbl); |
| 1605 __ CompareObject(ECX, two_byte_string_class); | 1604 __ CompareClassId(ECX, two_byte_string_class); |
| 1606 __ j(EQUAL, is_instance_lbl); | 1605 __ j(EQUAL, is_instance_lbl); |
| 1607 __ CompareObject(ECX, four_byte_string_class); | 1606 __ CompareClassId(ECX, four_byte_string_class); |
| 1608 __ j(EQUAL, is_instance_lbl); | 1607 __ j(EQUAL, is_instance_lbl); |
| 1609 } else if (type.IsFunctionInterface()) { | 1608 } else if (type.IsFunctionInterface()) { |
| 1610 // Check if instance is a closure. | 1609 // Check if instance is a closure. |
| 1611 const Immediate raw_null = | 1610 const Immediate raw_null = |
| 1612 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1611 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1613 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1612 __ GetClassOf(ECX, EAX, EBX); |
| 1614 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset())); | 1613 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset())); |
| 1615 __ cmpl(ECX, raw_null); | 1614 __ cmpl(ECX, raw_null); |
| 1616 __ j(NOT_EQUAL, is_instance_lbl); | 1615 __ j(NOT_EQUAL, is_instance_lbl); |
| 1617 } | 1616 } |
| 1618 // Otherwise fallthrough. | 1617 // Otherwise fallthrough. |
| 1619 } | 1618 } |
| 1620 | 1619 |
| 1621 | 1620 |
| 1622 // EAX: instance to test. | 1621 // EAX: instance to test. |
| 1623 // Clobbers: EBX, EDX, ECX. | 1622 // Clobbers: EBX, EDX, ECX. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1639 // Type arguments are on stack. | 1638 // Type arguments are on stack. |
| 1640 __ popl(EBX); | 1639 __ popl(EBX); |
| 1641 // Check if type argument is dynamic. | 1640 // Check if type argument is dynamic. |
| 1642 __ cmpl(EBX, raw_null); | 1641 __ cmpl(EBX, raw_null); |
| 1643 __ j(EQUAL, is_instance_lbl); | 1642 __ j(EQUAL, is_instance_lbl); |
| 1644 | 1643 |
| 1645 // EBX: instantiator type arguments. | 1644 // EBX: instantiator type arguments. |
| 1646 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. | 1645 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. |
| 1647 // We expect that frequently checked objects wull have their type arguments | 1646 // We expect that frequently checked objects wull have their type arguments |
| 1648 // converted into instance of TypeArguments. | 1647 // converted into instance of TypeArguments. |
| 1649 __ movl(EDX, FieldAddress(EBX, Object::class_offset())); | 1648 __ CompareClassOf(EBX, Class::Handle(Object::type_arguments_class()), EDX); |
| 1650 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class())); | |
| 1651 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1649 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1652 | 1650 |
| 1653 __ movl(EDX, | 1651 __ movl(EDX, |
| 1654 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); | 1652 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); |
| 1655 // EDX: concrete type of type. | 1653 // EDX: concrete type of type. |
| 1656 // Check if type argument is dynamic. | 1654 // Check if type argument is dynamic. |
| 1657 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); | 1655 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); |
| 1658 __ j(EQUAL, is_instance_lbl); | 1656 __ j(EQUAL, is_instance_lbl); |
| 1659 __ cmpl(EDX, raw_null); | 1657 __ cmpl(EDX, raw_null); |
| 1660 __ j(EQUAL, is_instance_lbl); | 1658 __ j(EQUAL, is_instance_lbl); |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1872 Label runtime_call, done; | 1870 Label runtime_call, done; |
| 1873 __ movl(EAX, Address(ESP, 0)); | 1871 __ movl(EAX, Address(ESP, 0)); |
| 1874 __ cmpl(EAX, raw_null); | 1872 __ cmpl(EAX, raw_null); |
| 1875 __ j(EQUAL, &runtime_call, Assembler::kNearJump); | 1873 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 1876 __ testl(EAX, Immediate(kSmiTagMask)); | 1874 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1877 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi. | 1875 __ j(ZERO, &runtime_call, Assembler::kNearJump); // Call runtime for Smi. |
| 1878 // This check should pass if the receiver's class implements the interface | 1876 // This check should pass if the receiver's class implements the interface |
| 1879 // 'bool'. Check only class 'Bool' since it is the only legal implementation | 1877 // 'bool'. Check only class 'Bool' since it is the only legal implementation |
| 1880 // of the interface 'bool'. | 1878 // of the interface 'bool'. |
| 1881 const Class& bool_class = | 1879 const Class& bool_class = |
| 1882 Class::ZoneHandle(Isolate::Current()->object_store()->bool_class()); | 1880 Class::Handle(Isolate::Current()->object_store()->bool_class()); |
| 1883 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1881 __ CompareClassOf(EAX, bool_class, ECX); |
| 1884 __ CompareObject(ECX, bool_class); | |
| 1885 __ j(EQUAL, &done, Assembler::kNearJump); | 1882 __ j(EQUAL, &done, Assembler::kNearJump); |
| 1886 | 1883 |
| 1887 __ Bind(&runtime_call); | 1884 __ Bind(&runtime_call); |
| 1888 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. | 1885 __ pushl(Immediate(Smi::RawValue(token_index))); // Source location. |
| 1889 __ pushl(EAX); // Push the source object. | 1886 __ pushl(EAX); // Push the source object. |
| 1890 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); | 1887 GenerateCallRuntime(node_id, token_index, kConditionTypeErrorRuntimeEntry); |
| 1891 // We should never return here. | 1888 // We should never return here. |
| 1892 __ int3(); | 1889 __ int3(); |
| 1893 | 1890 |
| 1894 __ Bind(&done); | 1891 __ Bind(&done); |
| (...skipping 621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2516 __ cmpl(EAX, raw_null); | 2513 __ cmpl(EAX, raw_null); |
| 2517 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 2514 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 2518 } | 2515 } |
| 2519 // Instantiate non-null type arguments. | 2516 // Instantiate non-null type arguments. |
| 2520 if (type_arguments.IsUninstantiatedIdentity()) { | 2517 if (type_arguments.IsUninstantiatedIdentity()) { |
| 2521 // Check if the instantiator type argument vector is a TypeArguments of a | 2518 // Check if the instantiator type argument vector is a TypeArguments of a |
| 2522 // matching length and, if so, use it as the instantiated type_arguments. | 2519 // matching length and, if so, use it as the instantiated type_arguments. |
| 2523 // No need to check RAX for null (again), because a null instance will | 2520 // No need to check RAX for null (again), because a null instance will |
| 2524 // have the wrong class (Null instead of TypeArguments). | 2521 // have the wrong class (Null instead of TypeArguments). |
| 2525 Label type_arguments_uninstantiated; | 2522 Label type_arguments_uninstantiated; |
| 2526 __ LoadObject(ECX, Class::ZoneHandle(Object::type_arguments_class())); | 2523 __ CompareClassOf(EAX, |
| 2527 __ cmpl(ECX, FieldAddress(EAX, Object::class_offset())); | 2524 Class::Handle(Object::type_arguments_class()), |
| 2525 ECX); |
| 2528 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); | 2526 __ j(NOT_EQUAL, &type_arguments_uninstantiated, Assembler::kNearJump); |
| 2529 __ cmpl(FieldAddress(EAX, TypeArguments::length_offset()), | 2527 __ cmpl(FieldAddress(EAX, TypeArguments::length_offset()), |
| 2530 Immediate(Smi::RawValue(len))); | 2528 Immediate(Smi::RawValue(len))); |
| 2531 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); | 2529 __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump); |
| 2532 __ Bind(&type_arguments_uninstantiated); | 2530 __ Bind(&type_arguments_uninstantiated); |
| 2533 } | 2531 } |
| 2534 if (instantiate_type_arguments) { | 2532 if (instantiate_type_arguments) { |
| 2535 // A runtime call to instantiate the type arguments is required. | 2533 // A runtime call to instantiate the type arguments is required. |
| 2536 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 2534 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 2537 __ PushObject(type_arguments); | 2535 __ PushObject(type_arguments); |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2983 const Error& error = Error::Handle( | 2981 const Error& error = Error::Handle( |
| 2984 Parser::FormatError(script, token_index, "Error", format, args)); | 2982 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2985 va_end(args); | 2983 va_end(args); |
| 2986 Isolate::Current()->long_jump_base()->Jump(1, error); | 2984 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2987 UNREACHABLE(); | 2985 UNREACHABLE(); |
| 2988 } | 2986 } |
| 2989 | 2987 |
| 2990 } // namespace dart | 2988 } // namespace dart |
| 2991 | 2989 |
| 2992 #endif // defined TARGET_ARCH_IA32 | 2990 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |