| 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 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1285 return &cls; | 1285 return &cls; |
| 1286 } | 1286 } |
| 1287 | 1287 |
| 1288 | 1288 |
| 1289 // Instance to test is in EAX. Test if its class is in subtype test cache array | 1289 // Instance to test is in EAX. Test if its class is in subtype test cache array |
| 1290 // and use the result in the array to jump to one of the labels. Fall through | 1290 // and use the result in the array to jump to one of the labels. Fall through |
| 1291 // if the instance is not in the cache array. | 1291 // if the instance is not in the cache array. |
| 1292 // TODO(srdjan): Implement a quicker subtype check, as type test | 1292 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 1293 // arrays can grow too high, but they may be useful when optimizing | 1293 // arrays can grow too high, but they may be useful when optimizing |
| 1294 // code (type-feedback). | 1294 // code (type-feedback). |
| 1295 void CodeGenerator::GenerateSubtypeTestCacheLookup(intptr_t node_id, | 1295 void CodeGenerator::GenerateSubtype1TestCacheLookup( |
| 1296 intptr_t token_index, | 1296 intptr_t node_id, |
| 1297 const Class& type_class, | 1297 intptr_t token_index, |
| 1298 Label* is_instance_lbl, | 1298 const Class& type_class, |
| 1299 Label* is_not_instance_lbl) { | 1299 Label* is_instance_lbl, |
| 1300 Label* is_not_instance_lbl) { |
| 1300 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1301 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1301 const Immediate raw_null = | 1302 const Immediate raw_null = |
| 1302 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1303 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1303 Label loop, found_in_cache, runtime_call; | 1304 Label loop, found_in_cache, runtime_call; |
| 1304 // Check immediate equality. | 1305 // Check immediate equality. |
| 1305 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1306 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1306 // ECX: instance class. | 1307 // ECX: instance class. |
| 1307 __ CompareObject(ECX, type_class); | 1308 __ CompareObject(ECX, type_class); |
| 1308 __ j(EQUAL, is_instance_lbl); | 1309 __ j(EQUAL, is_instance_lbl); |
| 1309 | 1310 |
| 1310 // Check immediate superclass equality. | 1311 // Check immediate superclass equality. |
| 1311 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); | 1312 __ movl(EDI, FieldAddress(ECX, Class::super_type_offset())); |
| 1312 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); | 1313 __ movl(EDI, FieldAddress(EDI, Type::type_class_offset())); |
| 1313 __ CompareObject(EDI, type_class); | 1314 __ CompareObject(EDI, type_class); |
| 1314 __ j(EQUAL, is_instance_lbl); | 1315 __ j(EQUAL, is_instance_lbl); |
| 1315 | 1316 |
| 1316 // ECX: instance class. | |
| 1317 // Insert subtype test cache into the code stream. | |
| 1318 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1317 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); |
| 1319 __ LoadObject(EDX, Array::ZoneHandle( | 1318 __ LoadObject(EDX, Array::ZoneHandle( |
| 1320 Array::New(SubTypeTestCache::kNumEntries))); | 1319 Array::New(SubTypeTestCache::kNumEntries))); |
| 1321 // EDX: cache array. | 1320 __ pushl(EDX); // Cache array. |
| 1322 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag)); | 1321 __ pushl(EAX); // Instance. |
| 1323 __ Bind(&loop); | 1322 __ pushl(raw_null); // Unused |
| 1324 __ movl(EBX, Address(EDX, kWordSize * SubTypeTestCache::kInstanceClass)); | 1323 __ call(&StubCode::Subtype1TestCacheLabel()); |
| 1325 __ cmpl(ECX, EBX); | 1324 __ popl(EAX); // Discard. |
| 1326 __ j(EQUAL, &found_in_cache, Assembler::kNearJump); | 1325 __ popl(EAX); // Restore receiver. |
| 1327 __ addl(EDX, Immediate(kWordSize * SubTypeTestCache::kNumEntries)); | 1326 __ popl(EDX); // Discard. |
| 1328 __ cmpl(EBX, raw_null); | 1327 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1329 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | |
| 1330 __ jmp(&runtime_call, Assembler::kNearJump); | |
| 1331 | 1328 |
| 1332 __ Bind(&found_in_cache); | 1329 __ cmpl(ECX, raw_null); |
| 1333 __ movl(EDX, Address(EDX, kWordSize * SubTypeTestCache::kTestResult)); | 1330 __ j(EQUAL, &runtime_call, Assembler::kNearJump); |
| 1334 __ CompareObject(EDX, bool_true); | 1331 __ CompareObject(ECX, bool_true); |
| 1335 __ j(EQUAL, is_instance_lbl); | 1332 __ j(EQUAL, is_instance_lbl); |
| 1336 __ jmp(is_not_instance_lbl); | 1333 __ jmp(is_not_instance_lbl); |
| 1337 __ Bind(&runtime_call); | 1334 __ Bind(&runtime_call); |
| 1338 } | 1335 } |
| 1339 | 1336 |
| 1340 | 1337 |
| 1341 // Inline tests according to the 'type' being tested. Jump to labels | 1338 // Inline tests according to the 'type' being tested. Jump to labels |
| 1342 // if we can compute the type-test, otherwise fallthrough. | 1339 // if we can compute the type-test, otherwise fallthrough. |
| 1343 // EAX: instance to be tested, must be preserved. | 1340 // EAX: instance to be tested, must be preserved. |
| 1344 // Clobbers many registers. | 1341 // Clobbers many registers. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1360 is_not_instance_lbl); | 1357 is_not_instance_lbl); |
| 1361 // Fall through to runtime call. | 1358 // Fall through to runtime call. |
| 1362 } else { | 1359 } else { |
| 1363 GenerateInstantiatedTypeNoArgumentsTest(node_id, | 1360 GenerateInstantiatedTypeNoArgumentsTest(node_id, |
| 1364 token_index, | 1361 token_index, |
| 1365 type, | 1362 type, |
| 1366 is_instance_lbl, | 1363 is_instance_lbl, |
| 1367 is_not_instance_lbl); | 1364 is_not_instance_lbl); |
| 1368 // If test non-conclusive so far, try the inlined type-test cache. | 1365 // If test non-conclusive so far, try the inlined type-test cache. |
| 1369 // 'type' is known at compile time. | 1366 // 'type' is known at compile time. |
| 1370 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class, | 1367 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1371 is_instance_lbl, is_not_instance_lbl); | 1368 is_instance_lbl, is_not_instance_lbl); |
| 1372 } | 1369 } |
| 1373 } else { | 1370 } else { |
| 1374 GenerateUninstantiatedTypeTest(type, | 1371 GenerateUninstantiatedTypeTest(type, |
| 1375 token_index, | 1372 token_index, |
| 1376 is_instance_lbl); | 1373 is_instance_lbl); |
| 1377 } | 1374 } |
| 1378 } | 1375 } |
| 1379 | 1376 |
| 1380 | 1377 |
| 1381 // If instanceof type test cannot be performed successfully at compile time and | 1378 // If instanceof type test cannot be performed successfully at compile time and |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1519 if (is_raw_type) { | 1516 if (is_raw_type) { |
| 1520 // Dynamic type argument, check only classes. | 1517 // Dynamic type argument, check only classes. |
| 1521 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1518 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1522 if (type.IsListInterface()) { | 1519 if (type.IsListInterface()) { |
| 1523 // TODO(srdjan) also accept List<Object>. | 1520 // TODO(srdjan) also accept List<Object>. |
| 1524 __ CompareObject(ECX, *CoreClass("ObjectArray")); | 1521 __ CompareObject(ECX, *CoreClass("ObjectArray")); |
| 1525 __ j(EQUAL, is_instance_lbl); | 1522 __ j(EQUAL, is_instance_lbl); |
| 1526 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); | 1523 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); |
| 1527 __ j(EQUAL, is_instance_lbl); | 1524 __ j(EQUAL, is_instance_lbl); |
| 1528 } | 1525 } |
| 1529 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class, | 1526 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1530 is_instance_lbl, is_not_instance_lbl); | 1527 is_instance_lbl, is_not_instance_lbl); |
| 1531 return; | 1528 return; |
| 1532 } | 1529 } |
| 1533 // Note that the test below must be synced with the tests in | 1530 // Note that the test below must be synced with the tests in |
| 1534 // CodeGenerator::UpdateTestCache. | 1531 // CodeGenerator::UpdateTestCache. |
| 1535 // Inline checks for one type argument only. | 1532 // Inline checks for one type argument only. |
| 1536 if (type_arguments.Length() != 1) { | 1533 if (type_arguments.Length() != 1) { |
| 1537 return; | 1534 return; |
| 1538 } | 1535 } |
| 1539 const AbstractType& tp_argument = | 1536 const AbstractType& tp_argument = |
| 1540 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); | 1537 AbstractType::ZoneHandle(type_arguments.TypeAt(0)); |
| 1541 if (!tp_argument.IsType()) { | 1538 if (!tp_argument.IsType()) { |
| 1542 // E.g., it is a TypeParameter. | 1539 // E.g., it is a TypeParameter. |
| 1543 return; | 1540 return; |
| 1544 } | 1541 } |
| 1545 // Malformed type has been caught in the caller chain of this function. | 1542 // Malformed type has been caught in the caller chain of this function. |
| 1546 ASSERT(tp_argument.HasResolvedTypeClass()); | 1543 ASSERT(tp_argument.HasResolvedTypeClass()); |
| 1547 // Check if type argument is dynamic or Object. | 1544 // Check if type argument is dynamic or Object. |
| 1548 const Type& object_type = | 1545 const Type& object_type = |
| 1549 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1546 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1550 Error& malformed_error = Error::Handle(); | 1547 Error& malformed_error = Error::Handle(); |
| 1551 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { | 1548 if (object_type.IsSubtypeOf(tp_argument, &malformed_error)) { |
| 1552 // Instance class test only necessary. | 1549 // Instance class test only necessary. |
| 1553 GenerateSubtypeTestCacheLookup(node_id, token_index, type_class, | 1550 GenerateSubtype1TestCacheLookup(node_id, token_index, type_class, |
| 1554 is_instance_lbl, is_not_instance_lbl); | 1551 is_instance_lbl, is_not_instance_lbl); |
| 1555 return; | 1552 return; |
| 1556 } | 1553 } |
| 1557 Label inlined_check, fall_through; | 1554 Label inlined_check, fall_through; |
| 1558 const Immediate raw_null = | 1555 const Immediate raw_null = |
| 1559 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1556 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1560 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); | 1557 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); |
| 1561 __ LoadObject(EDX, Array::ZoneHandle( | 1558 __ LoadObject(EDX, Array::ZoneHandle( |
| 1562 Array::New(SubTypeTestCache::kNumEntries))); | 1559 Array::New(SubTypeTestCache::kNumEntries))); |
| 1563 __ pushl(EDX); // Cache array. | 1560 __ pushl(EDX); // Cache array. |
| 1564 __ pushl(EAX); // Instance. | 1561 __ pushl(EAX); // Instance. |
| 1565 __ pushl(raw_null); // Instantiator type arguments, no instantiator -> null. | 1562 __ pushl(raw_null); // Unused. |
| 1566 __ call(&StubCode::SubtypeTestCacheLabel()); | 1563 __ call(&StubCode::Subtype2TestCacheLabel()); |
| 1567 __ popl(EDX); // Discard. | 1564 __ popl(EAX); // Discard. |
| 1568 __ popl(EAX); // Restore receiver. | 1565 __ popl(EAX); // Restore receiver. |
| 1569 __ popl(EDX); // Discard. | 1566 __ popl(EDX); // Discard. |
| 1570 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. | 1567 // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False. |
| 1571 | 1568 |
| 1572 __ cmpl(ECX, raw_null); | 1569 __ cmpl(ECX, raw_null); |
| 1573 __ j(EQUAL, &fall_through, Assembler::kNearJump); | 1570 __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| 1574 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1571 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1575 __ CompareObject(ECX, bool_true); | 1572 __ CompareObject(ECX, bool_true); |
| 1576 __ j(EQUAL, is_instance_lbl); | 1573 __ j(EQUAL, is_instance_lbl); |
| 1577 __ jmp(is_not_instance_lbl); | 1574 __ jmp(is_not_instance_lbl); |
| (...skipping 1417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2995 const Error& error = Error::Handle( | 2992 const Error& error = Error::Handle( |
| 2996 Parser::FormatError(script, token_index, "Error", format, args)); | 2993 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2997 va_end(args); | 2994 va_end(args); |
| 2998 Isolate::Current()->long_jump_base()->Jump(1, error); | 2995 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2999 UNREACHABLE(); | 2996 UNREACHABLE(); |
| 3000 } | 2997 } |
| 3001 | 2998 |
| 3002 } // namespace dart | 2999 } // namespace dart |
| 3003 | 3000 |
| 3004 #endif // defined TARGET_ARCH_IA32 | 3001 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |