Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: runtime/vm/code_generator_ia32.cc

Issue 9844003: More type checking performance improvements and a bug fix in intrinsifier. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | runtime/vm/intrinsifier_ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | runtime/vm/intrinsifier_ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698