| 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 1295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1306 __ CompareObject(ECX, type_class); | 1306 __ CompareObject(ECX, type_class); |
| 1307 __ j(EQUAL, is_instance_lbl); | 1307 __ j(EQUAL, is_instance_lbl); |
| 1308 | 1308 |
| 1309 // Check immediate superclass equality. | 1309 // Check immediate superclass equality. |
| 1310 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 1310 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 1311 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 1311 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 1312 __ CompareObject(EDI, type_class); | 1312 __ CompareObject(EDI, type_class); |
| 1313 __ j(EQUAL, is_instance_lbl); | 1313 __ j(EQUAL, is_instance_lbl); |
| 1314 | 1314 |
| 1315 // ECX: instance class. | 1315 // ECX: instance class. |
| 1316 // Insert subtype test cache into the code stream. |
| 1316 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1317 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); |
| 1317 __ LoadObject(EDX, Array::ZoneHandle(Array::New(2))); | 1318 __ LoadObject(EDX, Array::ZoneHandle( |
| 1319 Array::New(SubTypeTestCache::kNumEntries))); |
| 1320 // EDX: cache array. |
| 1318 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag)); | 1321 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag)); |
| 1319 __ Bind(&loop); | 1322 __ Bind(&loop); |
| 1320 __ movl(EBX, Address(EDX, 0)); | 1323 __ movl(EBX, Address(EDX, kWordSize * SubTypeTestCache::kInstanceClass)); |
| 1321 __ cmpl(ECX, EBX); | 1324 __ cmpl(ECX, EBX); |
| 1322 __ j(EQUAL, &found_in_cache, Assembler::kNearJump); | 1325 __ j(EQUAL, &found_in_cache, Assembler::kNearJump); |
| 1323 __ addl(EDX, Immediate(kWordSize * 2)); | 1326 __ addl(EDX, Immediate(kWordSize * SubTypeTestCache::kNumEntries)); |
| 1324 __ cmpl(EBX, raw_null); | 1327 __ cmpl(EBX, raw_null); |
| 1325 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 1328 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1326 __ jmp(&runtime_call, Assembler::kNearJump); | 1329 __ jmp(&runtime_call, Assembler::kNearJump); |
| 1327 | 1330 |
| 1328 __ Bind(&found_in_cache); | 1331 __ Bind(&found_in_cache); |
| 1329 __ movl(EDX, Address(EDX, kWordSize)); | 1332 __ movl(EDX, Address(EDX, kWordSize * SubTypeTestCache::kTestResult)); |
| 1330 __ CompareObject(EDX, bool_true); | 1333 __ CompareObject(EDX, bool_true); |
| 1331 __ j(EQUAL, is_instance_lbl); | 1334 __ j(EQUAL, is_instance_lbl); |
| 1332 __ jmp(is_not_instance_lbl); | 1335 __ jmp(is_not_instance_lbl); |
| 1333 __ Bind(&runtime_call); | 1336 __ Bind(&runtime_call); |
| 1334 } | 1337 } |
| 1335 | 1338 |
| 1336 | 1339 |
| 1337 // Inline tests according to the 'type' being tested. Jump to labels | 1340 // Inline tests according to the 'type' being tested. Jump to labels |
| 1338 // if we can compute the type-test, otherwise fallthrough. | 1341 // if we can compute the type-test, otherwise fallthrough. |
| 1339 // EAX: instance to be tested. | 1342 // EAX: instance to be tested, must be preserved. |
| 1340 // Clobbers many registers. | 1343 // Clobbers many registers. |
| 1341 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id, | 1344 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id, |
| 1342 intptr_t token_index, | 1345 intptr_t token_index, |
| 1343 const AbstractType& type, | 1346 const AbstractType& type, |
| 1344 Label* is_instance_lbl, | 1347 Label* is_instance_lbl, |
| 1345 Label* is_not_instance_lbl) { | 1348 Label* is_not_instance_lbl) { |
| 1346 if (type.IsInstantiated()) { | 1349 if (type.IsInstantiated()) { |
| 1347 const Class& type_class = Class::ZoneHandle(type.type_class()); | 1350 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1348 // A Smi object cannot be the instance of a parameterized class. | 1351 // 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 | 1352 // A class equality check is only applicable with a dst type of a |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1545 // Check if type argument is dynamic or Object. | 1548 // Check if type argument is dynamic or Object. |
| 1546 const Type& object_type = | 1549 const Type& object_type = |
| 1547 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1550 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1548 Error& malformed_error = Error::Handle(); | 1551 Error& malformed_error = Error::Handle(); |
| 1549 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { | 1552 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 1550 // Instance class test only necessary. | 1553 // Instance class test only necessary. |
| 1551 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class, | 1554 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class, |
| 1552 is_instance_lbl, is_not_instance_lbl); | 1555 is_instance_lbl, is_not_instance_lbl); |
| 1553 return; | 1556 return; |
| 1554 } | 1557 } |
| 1555 // Efficient type argument check can be done only on known classes. | |
| 1556 const Type& list_type = | |
| 1557 Type::Handle(Isolate::Current()->object_store()->list_interface()); | |
| 1558 Label inlined_check, fall_through; | 1558 Label inlined_check, fall_through; |
| 1559 if (!list_type.IsSubtypeOf(type, &malformed_error)) { | |
| 1560 // Since we support only known subtypes of List, no need to emit code | |
| 1561 // otherwise. | |
| 1562 return; | |
| 1563 } | |
| 1564 // TODO(srdjan): Recognize somehow classes that are 'regular' i.e., which | |
| 1565 // type-parameters are simple structure. | |
| 1566 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1567 __ CompareObject(ECX, *CoreClass("ObjectArray")); | |
| 1568 __ j(EQUAL, &inlined_check); | |
| 1569 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | |
| 1570 __ j(NOT_EQUAL, &fall_through); | |
| 1571 __ Bind(&inlined_check); | |
| 1572 | |
| 1573 // First step is to check instance class. | |
| 1574 Label check_type_argument; | |
| 1575 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class, | |
| 1576 &check_type_argument, is_not_instance_lbl); | |
| 1577 // Class test not conclusive (fall-through). | |
| 1578 __ jmp(&fall_through); | |
| 1579 __ Bind(&check_type_argument); | |
| 1580 // Get type argument of instance. | |
| 1581 const Class& tp_argument_class = Class::ZoneHandle(tp_argument.type_class()); | |
| 1582 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | |
| 1583 __ movl(EDI, FieldAddress(ECX, | |
| 1584 tp_argument_class.type_arguments_instance_field_offset_offset())); | |
| 1585 // EDI: intptr_t offset of type arguments in instance. | |
| 1586 __ cmpl(EDI, Immediate(Class::kNoTypeArguments)); | |
| 1587 __ j(EQUAL, is_instance_lbl); | |
| 1588 __ movl(EDI, FieldAddress(EAX, EDI, TIMES_1, 0)); | |
| 1589 // EDI: type arguments of the instance. | |
| 1590 // Is type argument dynamic? | |
| 1591 const Immediate raw_null = | 1559 const Immediate raw_null = |
| 1592 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1560 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1593 __ cmpl(EDI, raw_null); | 1561 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); |
| 1562 __ LoadObject(EDX, Array::ZoneHandle( |
| 1563 Array::New(SubTypeTestCache::kNumEntries))); |
| 1564 __ pushl(EDX); // Cache array. |
| 1565 __ pushl(EAX); // Instance. |
| 1566 __ pushl(raw_null); // Instantiator type arguments, no instantiator -> null. |
| 1567 __ call(&StubCode::SubtypeTestCacheLabel()); |
| 1568 __ popl(EDX); // Discard. |
| 1569 __ popl(EAX); // Restore receiver. |
| 1570 __ popl(EDX); // Discard. |
| 1571 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1572 |
| 1573 __ cmpl(ECX, raw_null); |
| 1574 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1575 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1576 __ CompareObject(ECX, bool_true); |
| 1594 __ j(EQUAL, is_instance_lbl); | 1577 __ j(EQUAL, is_instance_lbl); |
| 1595 // Type arguments may be canonicalized: are they equal? | 1578 __ jmp(is_not_instance_lbl); |
| 1596 __ CompareObject(EDI, type_arguments); | |
| 1597 __ j(EQUAL, is_instance_lbl); | |
| 1598 | |
| 1599 // We can handle only type of class TypeArguments. | |
| 1600 __ movl(EDX, FieldAddress(EDI, Object::class_offset())); | |
| 1601 __ CompareObject(EDX, | |
| 1602 Object::ZoneHandle(Object::type_arguments_class())); | |
| 1603 __ j(NOT_EQUAL, &fall_through); | |
| 1604 // EDI: instance of class 'TypeArguments'. | |
| 1605 __ movl(EDX, FieldAddress(EDI, TypeArguments::length_offset())); | |
| 1606 // Handling only tests with one type argument. | |
| 1607 Immediate smi_one_imm = | |
| 1608 Immediate(reinterpret_cast<int32_t>(Smi::New(1))); | |
| 1609 __ cmpl(EDX, smi_one_imm); | |
| 1610 __ j(NOT_EQUAL, &fall_through); | |
| 1611 __ movl(ECX, FieldAddress(EDI, TypeArguments::type_at_offset(0))); | |
| 1612 __ CompareObject(ECX, tp_argument); | |
| 1613 __ j(EQUAL, is_instance_lbl); | |
| 1614 // If the type is not parameterized do the subclass check. | |
| 1615 if (!tp_argument_class.HasTypeArguments()) { | |
| 1616 __ LoadObject(EDX, tp_argument_class); | |
| 1617 __ movl(ECX, FieldAddress(ECX, Type::type_class_offset())); | |
| 1618 __ cmpl(ECX, EDX); | |
| 1619 __ j(EQUAL, is_instance_lbl); | |
| 1620 // A non-parameterized class is in EDX, compare with class in ECX | |
| 1621 // EAX, EDX are preserved in stub. | |
| 1622 __ call(&StubCode::IsRawSubTypeLabel()); | |
| 1623 // Result in EBX: 1 is raw subtype. | |
| 1624 __ cmpl(EBX, Immediate(1)); | |
| 1625 __ j(EQUAL, is_instance_lbl); | |
| 1626 } | |
| 1627 // Fall through if type test is not conclusive. | |
| 1628 __ Bind(&fall_through); | 1579 __ Bind(&fall_through); |
| 1629 } | 1580 } |
| 1630 | 1581 |
| 1631 | 1582 |
| 1632 // EAX: instance to test. | 1583 // EAX: instance to test. |
| 1633 // Clobbers: EBX, ECX, EDX. | 1584 // Clobbers: EBX, ECX, EDX. |
| 1634 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( | 1585 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( |
| 1635 intptr_t node_id, | 1586 intptr_t node_id, |
| 1636 intptr_t token_index, | 1587 intptr_t token_index, |
| 1637 const AbstractType& type, | 1588 const AbstractType& type, |
| (...skipping 1378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3016 const Error& error = Error::Handle( | 2967 const Error& error = Error::Handle( |
| 3017 Parser::FormatError(script, token_index, "Error", format, args)); | 2968 Parser::FormatError(script, token_index, "Error", format, args)); |
| 3018 va_end(args); | 2969 va_end(args); |
| 3019 Isolate::Current()->long_jump_base()->Jump(1, error); | 2970 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 3020 UNREACHABLE(); | 2971 UNREACHABLE(); |
| 3021 } | 2972 } |
| 3022 | 2973 |
| 3023 } // namespace dart | 2974 } // namespace dart |
| 3024 | 2975 |
| 3025 #endif // defined TARGET_ARCH_IA32 | 2976 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |