| 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 1427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1438 // TODO(srdjan) also accept List<Object>. | 1438 // TODO(srdjan) also accept List<Object>. |
| 1439 __ CompareObject(ECX, *CoreClass("ObjectArray")); | 1439 __ CompareObject(ECX, *CoreClass("ObjectArray")); |
| 1440 __ j(EQUAL, is_instance_lbl); | 1440 __ j(EQUAL, is_instance_lbl); |
| 1441 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | 1441 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); |
| 1442 __ j(EQUAL, is_instance_lbl); | 1442 __ j(EQUAL, is_instance_lbl); |
| 1443 } | 1443 } |
| 1444 return | 1444 return |
| 1445 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, | 1445 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1446 is_instance_lbl, is_not_instance_lbl); | 1446 is_instance_lbl, is_not_instance_lbl); |
| 1447 } | 1447 } |
| 1448 // Note that the test below must be synced with the tests in | 1448 // If one type argument only, quick check. |
| 1449 // CodeGenerator::UpdateTestCache. | 1449 if (type_arguments.Length() == 1) { |
| 1450 // Inline checks for one type argument only. | 1450 const AbstractType& tp_argument = AbstractType::ZoneHandle( |
| 1451 if (type_arguments.Length() != 1) { | 1451 type_arguments.TypeAt(0)); |
| 1452 return SubtypeTestCache::null(); | 1452 if (tp_argument.IsType()) { |
| 1453 } | 1453 // Malformed type has been caught in the caller chain of this function. |
| 1454 const AbstractType& tp_argument = | 1454 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 1455 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); | 1455 // Check if type argument is dynamic or Object. |
| 1456 if (!tp_argument.IsType()) { | 1456 const Type& object_type = |
| 1457 // E.g., it is a TypeParameter. | 1457 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1458 return SubtypeTestCache::null(); | 1458 Error& malformed_error = Error::Handle(); |
| 1459 } | 1459 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 1460 // Malformed type has been caught in the caller chain of this function. | 1460 // Instance class test only necessary. |
| 1461 ASSERT(tp_argument.HasResolvedTypeClass()); | 1461 return GenerateSubtype1TestCacheLookup( |
| 1462 // Check if type argument is dynamic or Object. | 1462 node_id, |
| 1463 const Type& object_type = | 1463 token_index, |
| 1464 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1464 type_class, |
| 1465 Error& malformed_error = Error::Handle(); | 1465 is_instance_lbl, |
| 1466 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { | 1466 is_not_instance_lbl); |
| 1467 // Instance class test only necessary. | 1467 } |
| 1468 return GenerateSubtype1TestCacheLookup( | 1468 } |
| 1469 node_id, token_index, type_class, is_instance_lbl, is_not_instance_lbl); | |
| 1470 } | 1469 } |
| 1471 const SubtypeTestCache& type_test_cache = | 1470 const SubtypeTestCache& type_test_cache = |
| 1472 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 1471 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1473 Label inlined_check, fall_through; | 1472 Label inlined_check, fall_through; |
| 1474 const Immediate raw_null = | 1473 const Immediate raw_null = |
| 1475 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1474 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1476 __ LoadObject(EDX, type_test_cache); | 1475 __ LoadObject(EDX, type_test_cache); |
| 1477 __ pushl(EDX); // Subtype test cache. | 1476 __ pushl(EDX); // Subtype test cache. |
| 1478 __ pushl(EAX); // Instance. | 1477 __ pushl(EAX); // Instance. |
| 1479 __ pushl(raw_null); // Unused. | 1478 __ pushl(raw_null); // Unused. |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1606 // EAX must be preserved! | 1605 // EAX must be preserved! |
| 1607 Label fall_through; | 1606 Label fall_through; |
| 1608 const bool kPushInstantiator = false; | 1607 const bool kPushInstantiator = false; |
| 1609 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); | 1608 GenerateInstantiatorTypeArguments(token_index, kPushInstantiator); |
| 1610 // Type arguments are on stack. | 1609 // Type arguments are on stack. |
| 1611 __ popl(EBX); | 1610 __ popl(EBX); |
| 1612 // Check if type argument is dynamic. | 1611 // Check if type argument is dynamic. |
| 1613 __ cmpl(EBX, raw_null); | 1612 __ cmpl(EBX, raw_null); |
| 1614 __ j(EQUAL, is_instance_lbl); | 1613 __ j(EQUAL, is_instance_lbl); |
| 1615 | 1614 |
| 1615 // EBX: instantiator type arguments. |
| 1616 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. | 1616 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. |
| 1617 // We expect that frequently checked objects wull have their type arguments |
| 1618 // converted into instance of TypeArguments. |
| 1617 __ movl(EDX, FieldAddress(EBX, Object::class_offset())); | 1619 __ movl(EDX, FieldAddress(EBX, Object::class_offset())); |
| 1618 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class())); | 1620 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class())); |
| 1619 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1621 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1620 | 1622 |
| 1621 // EBX: Instance of TypeArguments. | |
| 1622 __ movl(EDX, | 1623 __ movl(EDX, |
| 1623 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); | 1624 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); |
| 1624 // EDX: concrete type of type. | 1625 // EDX: concrete type of type. |
| 1625 // Check if type argument is dynamic. | 1626 // Check if type argument is dynamic. |
| 1626 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); | 1627 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); |
| 1627 __ j(EQUAL, is_instance_lbl); | 1628 __ j(EQUAL, is_instance_lbl); |
| 1629 __ cmpl(EDX, raw_null); |
| 1630 __ j(EQUAL, is_instance_lbl); |
| 1628 | 1631 |
| 1629 // Check if the type has type parameters, if not do the class comparison. | 1632 // For Smi check quickly against int and num interfaces. |
| 1630 Label not_smi; | 1633 Label not_smi; |
| 1631 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? | 1634 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 1632 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 1635 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 1633 // For Smi check quickly against int and num interfaces. | |
| 1634 __ CompareObject(EDX, Type::ZoneHandle(Type::IntInterface())); | 1636 __ CompareObject(EDX, Type::ZoneHandle(Type::IntInterface())); |
| 1635 __ j(EQUAL, is_instance_lbl); | 1637 __ j(EQUAL, is_instance_lbl); |
| 1636 __ CompareObject(EDX, Type::ZoneHandle(Type::NumberInterface())); | 1638 __ CompareObject(EDX, Type::ZoneHandle(Type::NumberInterface())); |
| 1637 __ j(EQUAL, is_instance_lbl); | 1639 __ j(EQUAL, is_instance_lbl); |
| 1638 __ jmp(&fall_through); | 1640 __ jmp(&fall_through); |
| 1639 | 1641 |
| 1640 __ Bind(¬_smi); | 1642 __ Bind(¬_smi); |
| 1643 // EBX: instantiator type arguments. |
| 1644 // EAX: instance |
| 1641 // The instantiated type parameter may not be a Type, but could be an | 1645 // The instantiated type parameter may not be a Type, but could be an |
| 1642 // InstantiatedType. It is therefore necessary to check its class. | 1646 // InstantiatedType. It is therefore necessary to check its class. |
| 1643 __ movl(ECX, FieldAddress(EDX, Object::class_offset())); | 1647 const SubtypeTestCache& type_test_cache = |
| 1644 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class())); | 1648 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1645 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1649 __ LoadObject(ECX, type_test_cache); |
| 1646 | 1650 __ pushl(ECX); // Subtype test cache. |
| 1647 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset())); | 1651 __ pushl(EAX); // Instance. |
| 1648 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset())); | 1652 __ pushl(EBX); // Instantator type arguments. |
| 1649 // Check that class of type has no type parameters. | 1653 __ call(&StubCode::Subtype3TestCacheLabel()); |
| 1654 __ popl(EDX); // Discard type arguments. |
| 1655 __ popl(EAX); // Restore receiver. |
| 1656 __ popl(EDX); // Discard subtype test cache. |
| 1657 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1650 __ cmpl(ECX, raw_null); | 1658 __ cmpl(ECX, raw_null); |
| 1651 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | 1659 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1652 // EAX has non-parameterized class. | 1660 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1653 // Check class equality | 1661 __ CompareObject(ECX, bool_true); |
| 1654 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1655 __ movl(ECX, FieldAddress(ECX, Type::type_class_offset())); | |
| 1656 __ cmpl(ECX, EDX); | |
| 1657 __ j(EQUAL, is_instance_lbl); | 1662 __ j(EQUAL, is_instance_lbl); |
| 1658 | 1663 __ jmp(is_not_instance_lbl); |
| 1659 // We have a non-parameterized class in EDX, compare with class of | |
| 1660 // value in EAX. EAX, EDX are preserved in stub. | |
| 1661 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1662 __ call(&StubCode::IsRawSubTypeLabel()); | |
| 1663 // Result in EBX: 1 is raw subtype. | |
| 1664 __ cmpl(EBX, Immediate(1)); | |
| 1665 __ j(EQUAL, is_instance_lbl); | |
| 1666 | |
| 1667 // Test not conclusive. | |
| 1668 __ Bind(&fall_through); | 1664 __ Bind(&fall_through); |
| 1669 return SubtypeTestCache::null(); | 1665 return type_test_cache.raw(); |
| 1670 } | 1666 } |
| 1671 if (type.IsType()) { | 1667 if (type.IsType()) { |
| 1672 Label fall_through; | 1668 Label fall_through; |
| 1673 __ testl(EAX, Immediate(kSmiTagMask)); // Is instance Smi? | 1669 __ testl(EAX, Immediate(kSmiTagMask)); // Is instance Smi? |
| 1674 __ j(ZERO, is_not_instance_lbl, Assembler::kNearJump); | 1670 __ j(ZERO, is_not_instance_lbl, Assembler::kNearJump); |
| 1675 // Uninstantiated type class is known at compile time, but the type | 1671 // Uninstantiated type class is known at compile time, but the type |
| 1676 // arguments are determined at runtime by the instantiator. | 1672 // arguments are determined at runtime by the instantiator. |
| 1677 const SubtypeTestCache& type_test_cache = | 1673 const SubtypeTestCache& type_test_cache = |
| 1678 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); | 1674 SubtypeTestCache::ZoneHandle(SubtypeTestCache::New()); |
| 1679 __ LoadObject(EDX, type_test_cache); | 1675 __ LoadObject(EDX, type_test_cache); |
| (...skipping 1278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2958 const Error& error = Error::Handle( | 2954 const Error& error = Error::Handle( |
| 2959 Parser::FormatError(script, token_index, "Error", format, args)); | 2955 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2960 va_end(args); | 2956 va_end(args); |
| 2961 Isolate::Current()->long_jump_base()->Jump(1, error); | 2957 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2962 UNREACHABLE(); | 2958 UNREACHABLE(); |
| 2963 } | 2959 } |
| 2964 | 2960 |
| 2965 } // namespace dart | 2961 } // namespace dart |
| 2966 | 2962 |
| 2967 #endif // defined TARGET_ARCH_IA32 | 2963 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |