Chromium Code Reviews| 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 1418 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1429 | 1429 |
| 1430 // Optimize assignable type check by adding inlined tests for: | 1430 // Optimize assignable type check by adding inlined tests for: |
| 1431 // - NULL -> return NULL. | 1431 // - NULL -> return NULL. |
| 1432 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1432 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1433 // - Class equality (only if class is not parameterized). | 1433 // - Class equality (only if class is not parameterized). |
| 1434 // Inputs: | 1434 // Inputs: |
| 1435 // - EAX: object. | 1435 // - EAX: object. |
| 1436 // Destroys ECX and EDX. | 1436 // Destroys ECX and EDX. |
| 1437 // Returns: | 1437 // Returns: |
| 1438 // - object in EAX for successful assignable check (or throws TypeError). | 1438 // - object in EAX for successful assignable check (or throws TypeError). |
| 1439 // Performance notes: positive checks must be quick, negative checks can be slow | |
| 1440 // as they throw an exception. | |
| 1439 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1441 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1440 intptr_t token_index, | 1442 intptr_t token_index, |
| 1441 const AbstractType& dst_type, | 1443 const AbstractType& dst_type, |
| 1442 const String& dst_name) { | 1444 const String& dst_name) { |
| 1443 ASSERT(FLAG_enable_type_checks); | 1445 ASSERT(FLAG_enable_type_checks); |
| 1444 ASSERT(token_index >= 0); | 1446 ASSERT(token_index >= 0); |
| 1445 ASSERT(!dst_type.IsNull()); | 1447 ASSERT(!dst_type.IsNull()); |
| 1446 ASSERT(dst_type.IsFinalized()); | 1448 ASSERT(dst_type.IsFinalized()); |
| 1447 | 1449 |
| 1448 // Any expression is assignable to the Dynamic type and to the Object type. | 1450 // Any expression is assignable to the Dynamic type and to the Object type. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1534 __ jmp(&done, Assembler::kNearJump); | 1536 __ jmp(&done, Assembler::kNearJump); |
| 1535 } else { | 1537 } else { |
| 1536 // Failed assignable type check: call runtime to throw TypeError. | 1538 // Failed assignable type check: call runtime to throw TypeError. |
| 1537 __ jmp(&runtime_call, Assembler::kNearJump); | 1539 __ jmp(&runtime_call, Assembler::kNearJump); |
| 1538 } | 1540 } |
| 1539 // Compare if the classes are equal. | 1541 // Compare if the classes are equal. |
| 1540 __ Bind(&compare_classes); | 1542 __ Bind(&compare_classes); |
| 1541 // If dst_type is an interface, we can skip the class equality check, | 1543 // If dst_type is an interface, we can skip the class equality check, |
| 1542 // because instances cannot be of an interface type. | 1544 // because instances cannot be of an interface type. |
| 1543 if (!dst_type_class.is_interface()) { | 1545 if (!dst_type_class.is_interface()) { |
| 1546 // Check if classes are equal. | |
| 1544 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1547 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1545 TestClassAndJump(dst_type_class, &done); // Uses ECX. | 1548 TestClassAndJump(dst_type_class, &done); // Uses ECX. |
| 1546 // Check superclass | 1549 // Check superclasses using a loop (faster than runtime call). |
| 1550 Label loop_done, loop; | |
|
sra1
2012/03/28 01:16:50
This is a test where Dart can be much faster than
srdjan
2012/03/28 01:46:23
Thanks. The purpose of this CL is to quickly elimi
| |
| 1551 __ Bind(&loop); | |
| 1552 // ECX: class. | |
| 1547 __ movl(ECX, FieldAddress(ECX, Class::super_type_offset())); | 1553 __ movl(ECX, FieldAddress(ECX, Class::super_type_offset())); |
| 1548 // Note that supertypes can't be NULL as every Dart instance has | 1554 // The supertype of Object is a null object. |
| 1549 // as supertype class Object. | 1555 __ cmpl(ECX, raw_null); |
| 1556 __ j(EQUAL, &loop_done, Assembler::kNearJump); | |
| 1550 __ movl(ECX, FieldAddress(ECX, Type::type_class_offset())); | 1557 __ movl(ECX, FieldAddress(ECX, Type::type_class_offset())); |
| 1551 TestClassAndJump(dst_type_class, &done); // Uses ECX. | 1558 TestClassAndJump(dst_type_class, &done); // Uses ECX. |
| 1559 __ jmp(&loop); | |
| 1560 __ Bind(&loop_done); | |
| 1552 } else { | 1561 } else { |
| 1553 // However, for specific core library interfaces, we can check for | 1562 // However, for specific core library interfaces, we can check for |
| 1554 // specific core library classes. | 1563 // specific core library classes. |
| 1555 Error& malformed_error = Error::Handle(); | 1564 Error& malformed_error = Error::Handle(); |
| 1556 if (dst_type.IsBoolInterface()) { | 1565 if (dst_type.IsBoolInterface()) { |
| 1557 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1566 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1558 const Class& bool_class = Class::ZoneHandle( | 1567 const Class& bool_class = Class::ZoneHandle( |
| 1559 Isolate::Current()->object_store()->bool_class()); | 1568 Isolate::Current()->object_store()->bool_class()); |
| 1560 TestClassAndJump(bool_class, &done); | 1569 TestClassAndJump(bool_class, &done); |
| 1561 } else if (dst_type.IsSubtypeOf( | 1570 } else if (dst_type.IsSubtypeOf( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1599 __ movl(EBX, FieldAddress(EBX, Class::interfaces_offset())); | 1608 __ movl(EBX, FieldAddress(EBX, Class::interfaces_offset())); |
| 1600 __ cmpl(EBX, raw_null); | 1609 __ cmpl(EBX, raw_null); |
| 1601 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1610 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1602 // Iterate over interfaces array and check if any of interfaces match. | 1611 // Iterate over interfaces array and check if any of interfaces match. |
| 1603 __ movl(EDI, FieldAddress(EBX, Array::length_offset())); | 1612 __ movl(EDI, FieldAddress(EBX, Array::length_offset())); |
| 1604 // EDI: array index | 1613 // EDI: array index |
| 1605 // EBX: array | 1614 // EBX: array |
| 1606 Label loop; | 1615 Label loop; |
| 1607 __ Bind(&loop); | 1616 __ Bind(&loop); |
| 1608 __ subl(EDI, Immediate(Smi::RawValue(1))); | 1617 __ subl(EDI, Immediate(Smi::RawValue(1))); |
| 1609 __ cmpl(EDI, Immediate(0)); | 1618 __ cmpl(EDI, Immediate(0)); |
|
sra1
2012/03/28 01:16:50
Should be unnecessary since SUB sets CC
srdjan
2012/03/28 01:46:23
Thanks. Next CL.
| |
| 1610 __ j(LESS, &runtime_call, Assembler::kNearJump); | 1619 __ j(LESS, &runtime_call, Assembler::kNearJump); |
| 1611 // EDI is Smi therefore TIMES_2 instead of TIMES_4. | 1620 // EDI is Smi therefore TIMES_2 instead of TIMES_4. |
| 1612 // Get type from array. | 1621 // Get type from array. |
| 1613 __ movl(ECX, FieldAddress(EBX, EDI, TIMES_2, Array::data_offset())); | 1622 __ movl(ECX, FieldAddress(EBX, EDI, TIMES_2, Array::data_offset())); |
| 1614 __ movl(ECX, FieldAddress(ECX, Type::type_class_offset())); | 1623 __ movl(ECX, FieldAddress(ECX, Type::type_class_offset())); |
| 1615 TestClassAndJump(dst_type_class, &done); // Uses ECX. | 1624 TestClassAndJump(dst_type_class, &done); // Uses ECX. |
| 1616 __ jmp(&loop, Assembler::kNearJump); | 1625 __ jmp(&loop, Assembler::kNearJump); |
| 1617 // Fall through to runtime code. | 1626 // Fall through to runtime code. |
| 1618 __ Bind(&fall_through); | 1627 __ Bind(&fall_through); |
| 1619 } | 1628 } |
| 1620 } | 1629 } |
| 1621 } | 1630 } |
| 1631 } else { | |
| 1632 ASSERT(!dst_type.IsInstantiated()); | |
| 1633 // Skip check if destination is a dynamic type. | |
| 1634 if (dst_type.IsTypeParameter()) { | |
| 1635 // EAX must be preserved! | |
| 1636 Label fall_through; | |
| 1637 GenerateInstantiatorTypeArguments(token_index); | |
| 1638 // Type arguments are on stack | |
| 1639 __ popl(EBX); | |
| 1640 // Check if dynamic. | |
| 1641 __ cmpl(EBX, raw_null); | |
| 1642 __ j(EQUAL, &done, Assembler::kNearJump); | |
| 1643 | |
| 1644 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. | |
| 1645 __ movl(EDX, FieldAddress(EBX, Object::class_offset())); | |
| 1646 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class())); | |
| 1647 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); | |
| 1648 __ movl(EDX, | |
| 1649 FieldAddress(EBX, TypeArguments::type_at_offset(dst_type.Index()))); | |
| 1650 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); | |
| 1651 __ j(EQUAL, &done, Assembler::kNearJump); | |
| 1652 __ Bind(&fall_through); | |
| 1653 } | |
| 1622 } | 1654 } |
| 1623 __ Bind(&runtime_call); | 1655 __ Bind(&runtime_call); |
| 1624 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1656 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1625 const Immediate location = | 1657 const Immediate location = |
| 1626 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | 1658 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1627 __ pushl(location); // Push the source location. | 1659 __ pushl(location); // Push the source location. |
| 1628 __ pushl(EAX); // Push the source object. | 1660 __ pushl(EAX); // Push the source object. |
| 1629 __ PushObject(dst_type); // Push the type of the destination. | 1661 __ PushObject(dst_type); // Push the type of the destination. |
| 1630 if (!dst_type.IsInstantiated()) { | 1662 if (dst_type.IsInstantiated()) { |
| 1663 __ pushl(raw_null); // Null instantiator. | |
| 1664 } else { | |
| 1631 GenerateInstantiatorTypeArguments(token_index); | 1665 GenerateInstantiatorTypeArguments(token_index); |
| 1632 } else { | |
| 1633 __ pushl(raw_null); // Null instantiator. | |
| 1634 } | 1666 } |
| 1635 __ PushObject(dst_name); // Push the name of the destination. | 1667 __ PushObject(dst_name); // Push the name of the destination. |
| 1636 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); | 1668 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); |
| 1637 // Pop the parameters supplied to the runtime entry. The result of the | 1669 // Pop the parameters supplied to the runtime entry. The result of the |
| 1638 // type check runtime call is the checked value. | 1670 // type check runtime call is the checked value. |
| 1639 __ addl(ESP, Immediate(5 * kWordSize)); | 1671 __ addl(ESP, Immediate(5 * kWordSize)); |
| 1640 __ popl(EAX); | 1672 __ popl(EAX); |
| 1641 | 1673 |
| 1674 // EAX: value. | |
| 1642 __ Bind(&done); | 1675 __ Bind(&done); |
| 1643 } | 1676 } |
| 1644 | 1677 |
| 1645 | 1678 |
| 1646 void CodeGenerator::GenerateArgumentTypeChecks() { | 1679 void CodeGenerator::GenerateArgumentTypeChecks() { |
| 1647 const Function& function = parsed_function_.function(); | 1680 const Function& function = parsed_function_.function(); |
| 1648 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 1681 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 1649 const int num_fixed_params = function.num_fixed_parameters(); | 1682 const int num_fixed_params = function.num_fixed_parameters(); |
| 1650 const int num_opt_params = function.num_optional_parameters(); | 1683 const int num_opt_params = function.num_optional_parameters(); |
| 1651 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); | 1684 ASSERT(num_fixed_params + num_opt_params <= scope->num_variables()); |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2223 // Restore the context. | 2256 // Restore the context. |
| 2224 __ popl(CTX); | 2257 __ popl(CTX); |
| 2225 // Result is in EAX. | 2258 // Result is in EAX. |
| 2226 if (IsResultNeeded(node)) { | 2259 if (IsResultNeeded(node)) { |
| 2227 __ pushl(EAX); | 2260 __ pushl(EAX); |
| 2228 } | 2261 } |
| 2229 } | 2262 } |
| 2230 | 2263 |
| 2231 | 2264 |
| 2232 // Pushes the type arguments of the instantiator on the stack. | 2265 // Pushes the type arguments of the instantiator on the stack. |
| 2266 // Destroys EBX. | |
| 2233 void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_index) { | 2267 void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_index) { |
| 2234 const Class& instantiator_class = Class::Handle( | 2268 const Class& instantiator_class = Class::Handle( |
| 2235 parsed_function().function().owner()); | 2269 parsed_function().function().owner()); |
| 2236 if (instantiator_class.NumTypeParameters() == 0) { | 2270 if (instantiator_class.NumTypeParameters() == 0) { |
| 2237 // The type arguments are compile time constants. | 2271 // The type arguments are compile time constants. |
| 2238 AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle(); | 2272 AbstractTypeArguments& type_arguments = AbstractTypeArguments::ZoneHandle(); |
| 2239 // TODO(regis): Temporary type should be allocated in new gen heap. | 2273 // TODO(regis): Temporary type should be allocated in new gen heap. |
| 2240 Type& type = Type::Handle( | 2274 Type& type = Type::Handle( |
| 2241 Type::New(instantiator_class, type_arguments, token_index)); | 2275 Type::New(instantiator_class, type_arguments, token_index)); |
| 2242 type ^= ClassFinalizer::FinalizeType( | 2276 type ^= ClassFinalizer::FinalizeType( |
| 2243 instantiator_class, type, ClassFinalizer::kFinalizeWellFormed); | 2277 instantiator_class, type, ClassFinalizer::kFinalizeWellFormed); |
| 2244 type_arguments = type.arguments(); | 2278 type_arguments = type.arguments(); |
| 2245 __ PushObject(type_arguments); | 2279 __ PushObject(type_arguments); |
| 2246 } else { | 2280 } else { |
| 2247 ASSERT(parsed_function().instantiator() != NULL); | 2281 ASSERT(parsed_function().instantiator() != NULL); |
| 2248 parsed_function().instantiator()->Visit(this); | 2282 parsed_function().instantiator()->Visit(this); |
| 2249 Function& outer_function = | 2283 Function& outer_function = |
| 2250 Function::Handle(parsed_function().function().raw()); | 2284 Function::Handle(parsed_function().function().raw()); |
| 2251 while (outer_function.IsLocalFunction()) { | 2285 while (outer_function.IsLocalFunction()) { |
| 2252 outer_function = outer_function.parent_function(); | 2286 outer_function = outer_function.parent_function(); |
| 2253 } | 2287 } |
| 2254 if (!outer_function.IsFactory()) { | 2288 if (!outer_function.IsFactory()) { |
| 2255 __ popl(EAX); // Pop instantiator. | 2289 __ popl(EBX); // Pop instantiator. |
| 2256 // The instantiator is the receiver of the caller, which is not a factory. | 2290 // The instantiator is the receiver of the caller, which is not a factory. |
| 2257 // The receiver cannot be null; extract its AbstractTypeArguments object. | 2291 // The receiver cannot be null; extract its AbstractTypeArguments object. |
| 2258 // Note that in the factory case, the instantiator is the first parameter | 2292 // Note that in the factory case, the instantiator is the first parameter |
| 2259 // of the factory, i.e. already an AbstractTypeArguments object. | 2293 // of the factory, i.e. already an AbstractTypeArguments object. |
| 2260 intptr_t type_arguments_instance_field_offset = | 2294 intptr_t type_arguments_instance_field_offset = |
| 2261 instantiator_class.type_arguments_instance_field_offset(); | 2295 instantiator_class.type_arguments_instance_field_offset(); |
| 2262 ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); | 2296 ASSERT(type_arguments_instance_field_offset != Class::kNoTypeArguments); |
| 2263 __ movl(EAX, FieldAddress(EAX, type_arguments_instance_field_offset)); | 2297 __ movl(EBX, FieldAddress(EBX, type_arguments_instance_field_offset)); |
| 2264 __ pushl(EAX); | 2298 __ pushl(EBX); |
| 2265 } | 2299 } |
| 2266 } | 2300 } |
| 2267 } | 2301 } |
| 2268 | 2302 |
| 2269 | 2303 |
| 2270 // Pushes the type arguments on the stack in preparation of a constructor or | 2304 // Pushes the type arguments on the stack in preparation of a constructor or |
| 2271 // factory call. | 2305 // factory call. |
| 2272 // For a factory call, instantiates (possibly requiring an additional run time | 2306 // For a factory call, instantiates (possibly requiring an additional run time |
| 2273 // call) and pushes the type argument vector that will be passed as implicit | 2307 // call) and pushes the type argument vector that will be passed as implicit |
| 2274 // first parameter to the factory. | 2308 // first parameter to the factory. |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2731 const Error& error = Error::Handle( | 2765 const Error& error = Error::Handle( |
| 2732 Parser::FormatError(script, token_index, "Error", format, args)); | 2766 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2733 va_end(args); | 2767 va_end(args); |
| 2734 Isolate::Current()->long_jump_base()->Jump(1, error); | 2768 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2735 UNREACHABLE(); | 2769 UNREACHABLE(); |
| 2736 } | 2770 } |
| 2737 | 2771 |
| 2738 } // namespace dart | 2772 } // namespace dart |
| 2739 | 2773 |
| 2740 #endif // defined TARGET_ARCH_IA32 | 2774 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |