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

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

Issue 10134069: Inline type check where type argument that we check against is instantiated. (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 | « runtime/vm/code_generator_ia32.h ('k') | no next file » | 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 1267 matching lines...) Expand 10 before | Expand all | Expand 10 after
1278 1278
1279 static const Class* CoreClass(const char* c_name) { 1279 static const Class* CoreClass(const char* c_name) {
1280 const String& class_name = String::Handle(String::NewSymbol(c_name)); 1280 const String& class_name = String::Handle(String::NewSymbol(c_name));
1281 const Class& cls = Class::ZoneHandle(Library::Handle( 1281 const Class& cls = Class::ZoneHandle(Library::Handle(
1282 Library::CoreImplLibrary()).LookupClass(class_name)); 1282 Library::CoreImplLibrary()).LookupClass(class_name));
1283 ASSERT(!cls.IsNull()); 1283 ASSERT(!cls.IsNull());
1284 return &cls; 1284 return &cls;
1285 } 1285 }
1286 1286
1287 1287
1288 // Instance to test is in EAX, test if it is a subtype of type_class. 1288 // Instance to test is in EAX. Test if its class is in subtype test cache array
1289 // The instance may not be a Smi (test before calling this). 1289 // and use the result in the array to jump to one of the labels. Fall through
1290 // The instance may not be NULL (test before calling this). 1290 // if the instance is not in the cache array.
1291 // TODO(srdjan): Implement a quicker subtype check, as type test 1291 // TODO(srdjan): Implement a quicker subtype check, as type test
1292 // arrays can grow too high, but they may be useful when optimizing 1292 // arrays can grow too high, but they may be useful when optimizing
1293 // code (type-feedback). 1293 // code (type-feedback).
1294 void CodeGenerator::GenerateClassTestCache(intptr_t node_id, 1294 void CodeGenerator::GenerateSubtypeTestCacheLookup(intptr_t node_id,
1295 intptr_t token_index, 1295 intptr_t token_index,
1296 const Class& type_class, 1296 const Class& type_class,
1297 Label* is_instance_lbl, 1297 Label* is_instance_lbl,
1298 Label* is_not_instance_lbl) { 1298 Label* is_not_instance_lbl) {
1299 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); 1299 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1300 const Immediate raw_null = 1300 const Immediate raw_null =
1301 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1301 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1302 Label loop, found_in_cache, runtime_call; 1302 Label loop, found_in_cache, runtime_call;
1303 // Check immediate equality. 1303 // Check immediate equality.
1304 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); 1304 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1305 // ECX: instance class. 1305 // ECX: instance class.
1306 __ CompareObject(ECX, type_class); 1306 __ CompareObject(ECX, type_class);
1307 __ j(EQUAL, is_instance_lbl); 1307 __ j(EQUAL, is_instance_lbl);
1308 1308
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1356 is_not_instance_lbl); 1356 is_not_instance_lbl);
1357 // Fall through to runtime call. 1357 // Fall through to runtime call.
1358 } else { 1358 } else {
1359 GenerateInstantiatedTypeNoArgumentsTest(node_id, 1359 GenerateInstantiatedTypeNoArgumentsTest(node_id,
1360 token_index, 1360 token_index,
1361 type, 1361 type,
1362 is_instance_lbl, 1362 is_instance_lbl,
1363 is_not_instance_lbl); 1363 is_not_instance_lbl);
1364 // If test non-conclusive so far, try the inlined type-test cache. 1364 // If test non-conclusive so far, try the inlined type-test cache.
1365 // 'type' is known at compile time. 1365 // 'type' is known at compile time.
1366 GenerateClassTestCache(node_id, token_index, type_class, 1366 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class,
1367 is_instance_lbl, is_not_instance_lbl); 1367 is_instance_lbl, is_not_instance_lbl);
1368 } 1368 }
1369 } else { 1369 } else {
1370 GenerateUninstantiatedTypeTest(type, 1370 GenerateUninstantiatedTypeTest(type,
1371 token_index, 1371 token_index,
1372 is_instance_lbl); 1372 is_instance_lbl);
1373 } 1373 }
1374 } 1374 }
1375 1375
1376 1376
1377 // If instanceof type test cannot be performed successfully at compile time and 1377 // If instanceof type test cannot be performed successfully at compile time and
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
1504 Label* is_not_instance_lbl) { 1504 Label* is_not_instance_lbl) {
1505 ASSERT(type.IsInstantiated()); 1505 ASSERT(type.IsInstantiated());
1506 const Class& type_class = Class::ZoneHandle(type.type_class()); 1506 const Class& type_class = Class::ZoneHandle(type.type_class());
1507 ASSERT(type_class.HasTypeArguments()); 1507 ASSERT(type_class.HasTypeArguments());
1508 // A Smi object cannot be the instance of a parameterized class. 1508 // A Smi object cannot be the instance of a parameterized class.
1509 // A class equality check is only applicable with a dst type of a 1509 // A class equality check is only applicable with a dst type of a
1510 // non-parameterized class or with a raw dst type of a parameterized class. 1510 // non-parameterized class or with a raw dst type of a parameterized class.
1511 __ testl(EAX, Immediate(kSmiTagMask)); 1511 __ testl(EAX, Immediate(kSmiTagMask));
1512 __ j(ZERO, is_not_instance_lbl); 1512 __ j(ZERO, is_not_instance_lbl);
1513 const AbstractTypeArguments& type_arguments = 1513 const AbstractTypeArguments& type_arguments =
1514 AbstractTypeArguments::Handle(type.arguments()); 1514 AbstractTypeArguments::ZoneHandle(type.arguments());
1515 const bool is_raw_type = type_arguments.IsNull() || 1515 const bool is_raw_type = type_arguments.IsNull() ||
1516 type_arguments.IsRaw(type_arguments.Length()); 1516 type_arguments.IsRaw(type_arguments.Length());
1517 if (is_raw_type) { 1517 if (is_raw_type) {
1518 // Dynamic type argument, check only classes. 1518 // Dynamic type argument, check only classes.
1519 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); 1519 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1520 if (type.IsListInterface()) { 1520 if (type.IsListInterface()) {
1521 // TODO(srdjan) also accept List<Object>. 1521 // TODO(srdjan) also accept List<Object>.
1522 __ CompareObject(ECX, *CoreClass("ObjectArray")); 1522 __ CompareObject(ECX, *CoreClass("ObjectArray"));
1523 __ j(EQUAL, is_instance_lbl); 1523 __ j(EQUAL, is_instance_lbl);
1524 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); 1524 __ CompareObject(ECX, *CoreClass("GrowableObjectArray"));
1525 __ j(EQUAL, is_instance_lbl); 1525 __ j(EQUAL, is_instance_lbl);
1526 } 1526 }
1527 GenerateClassTestCache(node_id, token_index, type_class, 1527 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class,
1528 is_instance_lbl, is_not_instance_lbl); 1528 is_instance_lbl, is_not_instance_lbl);
1529 return;
1529 } 1530 }
1530 // TODO(srdjan): do type test on type arguments. 1531 // Note that the test below must be synced withe the tests in
regis 2012/04/26 21:55:05 with
srdjan 2012/04/26 22:05:48 Done.
1531 // Fall through if type test is not conclusive 1532 // CodeGenerator::UpdateTestCache.
regis 2012/04/26 21:55:05 You could factorize the tests in an helper. This w
srdjan 2012/04/26 22:05:48 Will see to it in a next CL...
1533 // Inline checks for one type argument only.
1534 if (type_arguments.Length() != 1) {
1535 return;
1536 }
1537 const AbstractType& tp_argument =
1538 AbstractType::ZoneHandle(type_arguments.TypeAt(0));
1539 if (!tp_argument.IsType()) {
1540 // E.g., it is a TypeParameter.
1541 return;
1542 }
1543 // Malformed type has been caught in the caller chain of this function.
1544 ASSERT(tp_argument.HasResolvedTypeClass());
1545 // Check if type argument is dynamic or Object.
1546 const Type& object_type =
1547 Type::Handle(Isolate::Current()->object_store()->object_type());
1548 Error& malformed_error = Error::Handle();
1549 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) {
1550 // Instance class test only necessary.
1551 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class,
1552 is_instance_lbl, is_not_instance_lbl);
1553 return;
1554 }
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;
1559 if (!list_type.IsSubtypeOf(type, &malformed_error)) {
1560 // Since we support only known subtypes of List, no need to emit code
1561 // otehrwise.
regis 2012/04/26 21:55:05 otherwise
1562 return;
1563 }
1564 // TODO(srdjan): Recognize somehow classes that are 'regular' i.e., which
1565 // type-parameters are simple structure.
regis 2012/04/26 21:55:05 I do not quite understand this TODO, but it has yo
srdjan 2012/04/26 22:05:48 Just an ideas that I plan to sketch out. Maybe no
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 =
1592 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1593 __ cmpl(EDI, raw_null);
1594 __ j(EQUAL, is_instance_lbl);
1595 // Type arguments may be canonicalized: are they equal?
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);
1532 } 1629 }
1533 1630
1534 1631
1535 // EAX: instance to test. 1632 // EAX: instance to test.
1536 // Clobbers: EBX, ECX, EDX. 1633 // Clobbers: EBX, ECX, EDX.
1537 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( 1634 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest(
1538 intptr_t node_id, 1635 intptr_t node_id,
1539 intptr_t token_index, 1636 intptr_t token_index,
1540 const AbstractType& type, 1637 const AbstractType& type,
1541 Label* is_instance_lbl, 1638 Label* is_instance_lbl,
(...skipping 1377 matching lines...) Expand 10 before | Expand all | Expand 10 after
2919 const Error& error = Error::Handle( 3016 const Error& error = Error::Handle(
2920 Parser::FormatError(script, token_index, "Error", format, args)); 3017 Parser::FormatError(script, token_index, "Error", format, args));
2921 va_end(args); 3018 va_end(args);
2922 Isolate::Current()->long_jump_base()->Jump(1, error); 3019 Isolate::Current()->long_jump_base()->Jump(1, error);
2923 UNREACHABLE(); 3020 UNREACHABLE();
2924 } 3021 }
2925 3022
2926 } // namespace dart 3023 } // namespace dart
2927 3024
2928 #endif // defined TARGET_ARCH_IA32 3025 #endif // defined TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « runtime/vm/code_generator_ia32.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698