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

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

Issue 10025031: Factored out common cases for type tests, used by instance of and assert assigneable. Using inlined… (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 // Inline tests according to the 'type' being tested. Jump to labels
1289 // if we can compute the type-test, otherwise fallthrough.
1290 // EAX: instance to be tested.
1291 // Clobbers many registers.
1292 void CodeGenerator::GenerateInlineInstanceof(intptr_t node_id,
1293 intptr_t token_index,
1294 const AbstractType& type,
1295 Label* is_instance_lbl,
1296 Label* is_not_instance_lbl) {
1297 if (type.IsInstantiated()) {
1298 const Class& type_class = Class::ZoneHandle(type.type_class());
1299 // A Smi object cannot be the instance of a parameterized class.
1300 // A class equality check is only applicable with a dst type of a
1301 // non-parameterized class or with a raw dst type of a parameterized class.
1302 if (type_class.HasTypeArguments()) {
1303 GenerateInstantiatedTypeWithArgumentsTest(type,
1304 is_instance_lbl,
1305 is_not_instance_lbl);
1306 // Fall through to runtime call.
1307 } else {
1308 GenerateInstantiatedTypeNoArgumentsTest(node_id,
1309 token_index,
1310 type,
1311 is_instance_lbl,
1312 is_not_instance_lbl);
1313 // If test non-conclusive so far, try the inlined type-test cache.
1314 // 'type' is known at compile time.
1315 const Bool& bool_true = Bool::ZoneHandle(Bool::True());
1316 const Immediate raw_null =
1317 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1318 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1319 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index);
1320 __ LoadObject(EDX, Array::ZoneHandle(Array::New(2)));
1321 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag));
1322 Label loop, found_in_cache, runtime_call;
1323 __ Bind(&loop);
1324 __ movl(EBX, Address(EDX, 0));
1325 __ cmpl(ECX, EBX);
1326 __ j(EQUAL, &found_in_cache, Assembler::kNearJump);
1327 __ addl(EDX, Immediate(kWordSize * 2));
1328 __ cmpl(EBX, raw_null);
1329 __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
1330 __ jmp(&runtime_call, Assembler::kNearJump);
1331
1332 __ Bind(&found_in_cache);
1333 __ movl(EDX, Address(EDX, kWordSize));
1334 __ CompareObject(EDX, bool_true);
1335 __ j(EQUAL, is_instance_lbl);
1336 __ jmp(is_not_instance_lbl);
1337 __ Bind(&runtime_call);
1338 }
1339 } else {
1340 GenerateUninstantiatedTypeTest(type,
1341 token_index,
1342 is_instance_lbl);
1343 }
1344 }
1345
1346
1288 // If instanceof type test cannot be performed successfully at compile time and 1347 // If instanceof type test cannot be performed successfully at compile time and
1289 // therefore eliminated, optimize it by adding inlined tests for: 1348 // therefore eliminated, optimize it by adding inlined tests for:
1290 // - NULL -> return false. 1349 // - NULL -> return false.
1291 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1350 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1292 // - Class equality (only if class is not parameterized). 1351 // - Class equality (only if class is not parameterized).
1293 // Inputs: 1352 // Inputs:
1294 // - EAX: object. 1353 // - EAX: object.
1295 // Destroys ECX. 1354 // Destroys ECX.
1296 // Returns: 1355 // Returns:
1297 // - true or false on stack. 1356 // - true or false on stack.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 &malformed_error)) { 1393 &malformed_error)) {
1335 __ PushObject(negate_result ? bool_false : bool_true); 1394 __ PushObject(negate_result ? bool_false : bool_true);
1336 } else { 1395 } else {
1337 ASSERT(malformed_error.IsNull()); 1396 ASSERT(malformed_error.IsNull());
1338 __ PushObject(negate_result ? bool_true : bool_false); 1397 __ PushObject(negate_result ? bool_true : bool_false);
1339 } 1398 }
1340 } 1399 }
1341 return; 1400 return;
1342 } 1401 }
1343 1402
1403 Label is_instance_of, is_not_instance_of;
1344 const Immediate raw_null = 1404 const Immediate raw_null =
1345 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1405 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1346 Label done, check_negate_done; 1406 Label done;
1347 // If type is instantiated and non-parameterized, we can inline code 1407 // If type is instantiated and non-parameterized, we can inline code
1348 // checking whether the tested instance is a Smi. 1408 // checking whether the tested instance is a Smi.
1349 if (type.IsInstantiated()) { 1409 if (type.IsInstantiated()) {
1350 // A null object is only an instance of Object and Dynamic, which has 1410 // A null object is only an instance of Object and Dynamic, which has
1351 // already been checked above (if the type is instantiated). So we can 1411 // already been checked above (if the type is instantiated). So we can
1352 // return false here if the instance is null (and if the type is 1412 // return false here if the instance is null (and if the type is
1353 // instantiated). 1413 // instantiated).
1354 // We can only inline this null check if the type is instantiated at compile 1414 // We can only inline this null check if the type is instantiated at compile
1355 // time, since an uninstantiated type at compile time could be Object or 1415 // time, since an uninstantiated type at compile time could be Object or
1356 // Dynamic at run time. 1416 // Dynamic at run time.
1357 Label non_null; 1417 Label non_null;
1358 __ cmpl(EAX, raw_null); 1418 __ cmpl(EAX, raw_null);
1359 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); 1419 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump);
1360 __ PushObject(negate_result ? bool_true : bool_false); 1420 __ PushObject(negate_result ? bool_true : bool_false);
1361 __ jmp(&done, Assembler::kNearJump); 1421 __ jmp(&done);
1422 __ Bind(&non_null);
1423 }
1362 1424
1363 __ Bind(&non_null); 1425 GenerateInlineInstanceof(node_id, token_index, type,
1426 &is_instance_of, &is_not_instance_of);
1364 1427
1365 const Class& type_class = Class::ZoneHandle(type.type_class());
1366 const bool requires_type_arguments = type_class.HasTypeArguments();
1367 // A Smi object cannot be the instance of a parameterized class.
1368 // A class equality check is only applicable with a dst type of a
1369 // non-parameterized class or with a raw dst type of a parameterized class.
1370 if (requires_type_arguments) {
1371 const AbstractTypeArguments& type_arguments =
1372 AbstractTypeArguments::Handle(type.arguments());
1373 const bool is_raw_type = type_arguments.IsNull() ||
1374 type_arguments.IsRaw(type_arguments.Length());
1375 Label runtime_call;
1376 __ testl(EAX, Immediate(kSmiTagMask));
1377 __ j(ZERO, &runtime_call, Assembler::kNearJump);
1378 // Object not Smi.
1379 if (is_raw_type) {
1380 if (type.IsListInterface()) {
1381 Label push_result;
1382 // TODO(srdjan) also accept List<Object>.
1383 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1384 __ CompareObject(ECX, *CoreClass("ObjectArray"));
1385 __ j(EQUAL, &push_result, Assembler::kNearJump);
1386 __ CompareObject(ECX, *CoreClass("GrowableObjectArray"));
1387 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
1388 __ Bind(&push_result);
1389 __ PushObject(negate_result ? bool_false : bool_true);
1390 __ jmp(&done, Assembler::kNearJump);
1391 } else if (!type_class.is_interface()) {
1392 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1393 __ CompareObject(ECX, type_class);
1394 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump);
1395 __ PushObject(negate_result ? bool_false : bool_true);
1396 __ jmp(&done, Assembler::kNearJump);
1397 }
1398 }
1399 __ Bind(&runtime_call);
1400 // Fall through to runtime call.
1401 } else {
1402 ASSERT(!requires_type_arguments);
1403 // Test if object is Smi and for a couple known test-classes.
1404 Label compare_classes;
1405 __ testl(EAX, Immediate(kSmiTagMask));
1406 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
1407 // Object is Smi.
1408 const Class& smi_class = Class::Handle(Smi::Class());
1409 // TODO(regis): We should introduce a SmiType.
1410 Error& malformed_error = Error::Handle();
1411 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
1412 type_class,
1413 TypeArguments::Handle(),
1414 &malformed_error)) {
1415 __ PushObject(negate_result ? bool_false : bool_true);
1416 } else {
1417 __ PushObject(negate_result ? bool_true : bool_false);
1418 }
1419 __ jmp(&done, Assembler::kNearJump);
1420
1421 // Compare if the classes are equal.
1422 __ Bind(&compare_classes);
1423 // Note that in instanceof both positive and negative tests must be fast.
1424 if (type.IsBoolInterface()) {
1425 // Bool interface has only bool class.
1426 Label is_bool;
1427 const Class & bool_class = Class::ZoneHandle(
1428 Isolate::Current()->object_store()->bool_class());
1429 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1430 __ CompareObject(ECX, bool_class);
1431 __ j(EQUAL, &is_bool, Assembler::kNearJump);
1432 __ PushObject(negate_result ? bool_true : bool_false);
1433 __ jmp(&done);
1434 __ Bind(&is_bool);
1435 __ PushObject(negate_result ? bool_false : bool_true);
1436 __ Bind(&done);
1437 return;
1438 }
1439
1440 // EAX: instance being tested.
1441 // Optional quick equality check and then the type test cache test.
1442 Label loop, runtime_call, found_in_cache, cache_test;
1443 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1444 if (!type_class.is_interface()) {
1445 // Class equality test first.
1446 __ CompareObject(ECX, type_class);
1447 __ j(NOT_EQUAL, &cache_test, Assembler::kNearJump);
1448 // Equal!
1449 __ PushObject(negate_result ? bool_false : bool_true);
1450 __ jmp(&done, Assembler::kNearJump);
1451 }
1452 __ Bind(&cache_test);
1453 // TODO(srdjan): Convert other tests to this simple form.
1454 // Class we are testing against has no type arguments.
1455 // TODO(srdjan): Canonicalize initial array?
1456 // TODO(srdjan): Account for 'negate_result' in cache.
1457 // The type test array is null-terminated. Two consecutive
1458 // array elements correspond to one test:
1459 // array[i + 0] : class.
1460 // array[i + 1] : result for the class.
1461 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index);
1462 __ LoadObject(EDX, Array::ZoneHandle(Array::New(2)));
1463 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag));
1464 __ Bind(&loop);
1465 __ movl(EBX, Address(EDX, 0));
1466 __ cmpl(ECX, EBX);
1467 __ j(EQUAL, &found_in_cache, Assembler::kNearJump);
1468 __ addl(EDX, Immediate(kWordSize * 2));
1469 __ cmpl(EBX, raw_null);
1470 __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
1471 __ jmp(&runtime_call, Assembler::kNearJump);
1472 __ Bind(&found_in_cache);
1473 __ pushl(Address(EDX, kWordSize));
1474 __ jmp(&check_negate_done);
1475 __ Bind(&runtime_call);
1476 }
1477 }
1478 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1428 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1479 const Immediate location = 1429 const Immediate location =
1480 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); 1430 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index)));
1481 const Immediate node_id_as_smi = 1431 const Immediate node_id_as_smi =
1482 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id))); 1432 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id)));
1483 __ pushl(location); // Push the source location. 1433 __ pushl(location); // Push the source location.
1484 __ pushl(node_id_as_smi); // node-id. 1434 __ pushl(node_id_as_smi); // node-id.
1485 __ pushl(EAX); // Push the instance. 1435 __ pushl(EAX); // Push the instance.
1486 __ PushObject(type); // Push the type. 1436 __ PushObject(type); // Push the type.
1487 if (!type.IsInstantiated()) { 1437 if (!type.IsInstantiated()) {
1488 GenerateInstantiatorTypeArguments(token_index); 1438 GenerateInstantiatorTypeArguments(token_index);
1489 } else { 1439 } else {
1490 __ pushl(raw_null); // Null instantiator. 1440 __ pushl(raw_null); // Null instantiator.
1491 } 1441 }
1492 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); 1442 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry);
1493 // Pop the two parameters supplied to the runtime entry. The result of the 1443 // Pop the two parameters supplied to the runtime entry. The result of the
1494 // instanceof runtime call will be left as the result of the operation. 1444 // instanceof runtime call will be left as the result of the operation.
1495 __ addl(ESP, Immediate(5 * kWordSize)); 1445 __ addl(ESP, Immediate(5 * kWordSize));
1496 __ Bind(&check_negate_done); 1446 __ jmp(&done);
1497 if (negate_result) { 1447
1498 Label negate_done; 1448 __ Bind(&is_instance_of);
1499 __ popl(EDX); 1449 __ PushObject(negate_result ? bool_false: bool_true);
1500 __ LoadObject(EAX, bool_true); 1450 __ jmp(&done);
1501 __ cmpl(EDX, EAX); 1451 __ Bind(&is_not_instance_of);
1502 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); 1452 __ PushObject(negate_result ? bool_true: bool_false);
1503 __ LoadObject(EAX, bool_false);
1504 __ Bind(&negate_done);
1505 __ pushl(EAX);
1506 }
1507 __ Bind(&done); 1453 __ Bind(&done);
1508 } 1454 }
1509 1455
1510 1456
1511 // Jumps to label if ECX equals the given class. 1457 // Jumps to label if ECX equals the given class.
1512 // Inputs: 1458 // Inputs:
1513 // - ECX: tested class. 1459 // - ECX: tested class.
1514 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { 1460 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) {
regis 2012/04/19 20:10:40 Remove this helper.
srdjan 2012/04/19 20:12:49 Done.
1515 __ CompareObject(ECX, cls); 1461 __ CompareObject(ECX, cls);
1516 __ j(EQUAL, label, Assembler::kNearJump); 1462 __ j(EQUAL, label, Assembler::kNearJump);
1517 } 1463 }
1518 1464
1519 1465
1466 // EAX: instance to test.
1467 // Clobbers: ECX.
1468 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
1469 // type test is conclusive, otherwise fallthrough if a type test could not
1470 // be completed.
1471 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest(
1472 const AbstractType& type,
1473 Label* is_instance_lbl,
1474 Label* is_not_instance_lbl) {
1475 ASSERT(type.IsInstantiated());
1476 const Class& type_class = Class::ZoneHandle(type.type_class());
1477 ASSERT(type_class.HasTypeArguments());
1478 // A Smi object cannot be the instance of a parameterized class.
1479 // A class equality check is only applicable with a dst type of a
1480 // non-parameterized class or with a raw dst type of a parameterized class.
1481 __ testl(EAX, Immediate(kSmiTagMask));
1482 __ j(ZERO, is_not_instance_lbl);
1483 const AbstractTypeArguments& type_arguments =
1484 AbstractTypeArguments::Handle(type.arguments());
1485 const bool is_raw_type = type_arguments.IsNull() ||
1486 type_arguments.IsRaw(type_arguments.Length());
1487 if (is_raw_type) {
1488 // Dynamic type argument, check only classes.
1489 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1490 if (type.IsListInterface()) {
1491 // TODO(srdjan) also accept List<Object>.
1492 __ CompareObject(ECX, *CoreClass("ObjectArray"));
1493 __ j(EQUAL, is_instance_lbl);
1494 __ CompareObject(ECX, *CoreClass("GrowableObjectArray"));
1495 __ j(EQUAL, is_instance_lbl);
1496 } else if (!type_class.is_interface()) {
1497 __ CompareObject(ECX, type_class);
1498 __ j(EQUAL, is_instance_lbl);
1499 }
1500 } else {
1501 // TODO(srdjan): do type test on type arguments.
1502 }
1503 // Fall through if type test is not conclusive
1504 }
1505
1506
1507 // EAX: instance to test.
1508 // Clobbers: EBX, ECX, EDX.
1509 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest(
1510 intptr_t node_id,
1511 intptr_t token_index,
1512 const AbstractType& type,
1513 Label* is_instance_lbl,
1514 Label* is_not_instance_lbl) {
1515 ASSERT(type.IsInstantiated());
1516 const Class& type_class = Class::ZoneHandle(type.type_class());
1517 ASSERT(!type_class.HasTypeArguments());
1518
1519 Label compare_classes;
1520 __ testl(EAX, Immediate(kSmiTagMask));
1521 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
1522 // Instance is Smi, check directly.
1523 const Class& smi_class = Class::Handle(Smi::Class());
1524 // TODO(regis): We should introduce a SmiType.
1525 Error& malformed_error = Error::Handle();
1526 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
1527 type_class,
1528 TypeArguments::Handle(),
1529 &malformed_error)) {
1530 __ jmp(is_instance_lbl);
1531 } else {
1532 __ jmp(is_not_instance_lbl);
1533 }
1534 // Compare if the classes are equal.
1535 __ Bind(&compare_classes);
1536
1537 // Checking against interface.
1538 // However, for specific core library interfaces, we can check for
1539 // specific core library classes.
1540 if (type.IsBoolInterface()) {
1541 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1542 const Class& bool_class = Class::ZoneHandle(
1543 Isolate::Current()->object_store()->bool_class());
1544 __ CompareObject(ECX, bool_class);
1545 __ j(EQUAL, is_instance_lbl);
1546 return;
1547 }
1548 // If type is an interface, we can skip the class equality check,
1549 // because instances cannot be of an interface type.
1550 if (!type_class.is_interface()) {
1551 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1552 __ CompareObject(ECX, type_class);
1553 __ j(EQUAL, is_instance_lbl);
1554 }
1555 if (type.IsSubtypeOf(
1556 Type::Handle(Type::NumberInterface()), &malformed_error)) {
1557 // Custom checking for numbers (Smi, Mint, Bigint and Double)
1558 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1559 if (type.IsIntInterface() || type.IsNumberInterface()) {
1560 // We already checked for Smi above.
1561 const Class& mint_class = Class::ZoneHandle(
1562 Isolate::Current()->object_store()->mint_class());
1563 const Class& bigint_class = Class::ZoneHandle(
1564 Isolate::Current()->object_store()->bigint_class());
1565 __ CompareObject(ECX, mint_class);
1566 __ j(EQUAL, is_instance_lbl);
1567 __ CompareObject(ECX, bigint_class);
1568 __ j(EQUAL, is_instance_lbl);
1569 }
1570 if (type.IsDoubleInterface() || type.IsNumberInterface()) {
1571 const Class& double_class = Class::ZoneHandle(
1572 Isolate::Current()->object_store()->double_class());
1573 __ CompareObject(ECX, double_class);
1574 __ j(EQUAL, is_instance_lbl);
1575 }
1576 } else if (type.IsStringInterface()) {
1577 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1578 const Class& one_byte_string_class = Class::ZoneHandle(
1579 Isolate::Current()->object_store()->one_byte_string_class());
1580 const Class& two_byte_string_class = Class::ZoneHandle(
1581 Isolate::Current()->object_store()->two_byte_string_class());
1582 const Class& four_byte_string_class = Class::ZoneHandle(
1583 Isolate::Current()->object_store()->four_byte_string_class());
1584 __ CompareObject(ECX, one_byte_string_class);
1585 __ j(EQUAL, is_instance_lbl);
1586 __ CompareObject(ECX, two_byte_string_class);
1587 __ j(EQUAL, is_instance_lbl);
1588 __ CompareObject(ECX, four_byte_string_class);
1589 __ j(EQUAL, is_instance_lbl);
1590 } else if (type.IsFunctionInterface()) {
1591 // Check if instance is a closure.
1592 const Immediate raw_null =
1593 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1594 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1595 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset()));
1596 __ cmpl(ECX, raw_null);
1597 __ j(NOT_EQUAL, is_instance_lbl);
1598 }
1599 // Otherwise fallthrough.
1600 }
1601
1602
1603 // EAX: instance to test.
1604 // Clobbers: EBX, EDX, ECX.
1605 void CodeGenerator::GenerateUninstantiatedTypeTest(
1606 const AbstractType& type,
1607 intptr_t token_index,
1608 Label* is_instance_lbl) {
1609 ASSERT(!type.IsInstantiated());
1610 // Skip check if destination is a dynamic type.
1611 if (type.IsTypeParameter()) {
1612 const Immediate raw_null =
1613 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1614 // EAX must be preserved!
1615 Label fall_through;
1616 GenerateInstantiatorTypeArguments(token_index);
1617 // Type arguments are on stack.
1618 __ popl(EBX);
1619 // Check if type argument is dynamic.
1620 __ cmpl(EBX, raw_null);
1621 __ j(EQUAL, is_instance_lbl);
1622
1623 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
1624 __ movl(EDX, FieldAddress(EBX, Object::class_offset()));
1625 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class()));
1626 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1627
1628 // EBX: Instance of TypeArguments.
1629 __ movl(EDX,
1630 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index())));
1631 // EDX: concrete type of type.
1632 // Check if type argument is dynamic.
1633 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType()));
1634 __ j(EQUAL, is_instance_lbl);
1635
1636 // Check if the type has type parameters, if not do the class comparison.
1637 Label not_smi;
1638 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi?
1639 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
1640 // For Smi check quickly against int and num interfaces.
1641 __ CompareObject(EDX, Type::ZoneHandle(Type::IntInterface()));
1642 __ j(EQUAL, is_instance_lbl);
1643 __ CompareObject(EDX, Type::ZoneHandle(Type::NumberInterface()));
1644 __ j(EQUAL, is_instance_lbl);
1645 __ jmp(&fall_through);
1646
1647 __ Bind(&not_smi);
1648 // The instantiated type parameter may not be a Type, but could be an
1649 // InstantiatedType. It is therefore necessary to check its class.
1650 __ movl(ECX, FieldAddress(EDX, Object::class_offset()));
1651 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class()));
1652 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1653
1654 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset()));
1655 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset()));
1656 // Check that class of type has no type parameters.
1657 __ cmpl(ECX, raw_null);
1658 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1659 // We have a non-parameterized class in EDX, compare with class of
1660 // value in EAX. EAX, EDX are preserved in stub.
1661 __ call(&StubCode::IsRawSubTypeLabel());
1662 // Result in EBX: 1 is raw subtype.
1663 __ cmpl(EBX, Immediate(1));
1664 __ j(EQUAL, is_instance_lbl);
1665
1666 // Test not conclusive.
1667 __ Bind(&fall_through);
1668 }
1669 }
1670
1671
1520 // If type check cannot be performed successfully at compile time and therefore 1672 // If type check cannot be performed successfully at compile time and therefore
1521 // eliminated, optimize it by adding inlined tests for: 1673 // eliminated, optimize it by adding inlined tests for:
1522 // - NULL -> return NULL. 1674 // - NULL -> return NULL.
1523 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1675 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1524 // - Class equality (only if class is not parameterized). 1676 // - Class equality (only if class is not parameterized).
1525 // Inputs: 1677 // Inputs:
1526 // - EAX: object. 1678 // - EAX: object.
1527 // Destroys ECX and EDX. 1679 // Destroys ECX and EDX.
1528 // Returns: 1680 // Returns:
1529 // - object in EAX for successful assignable check (or throws TypeError). 1681 // - object in EAX for successful assignable check (or throws TypeError).
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1595 __ PushObject(dst_name); // Push the name of the destination. 1747 __ PushObject(dst_name); // Push the name of the destination.
1596 __ PushObject(error_message); 1748 __ PushObject(error_message);
1597 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); 1749 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry);
1598 // We should never return here. 1750 // We should never return here.
1599 __ int3(); 1751 __ int3();
1600 1752
1601 __ Bind(&done); // For a null object. 1753 __ Bind(&done); // For a null object.
1602 return; 1754 return;
1603 } 1755 }
1604 1756
1605 // If dst_type is instantiated and non-parameterized, we can inline code 1757 GenerateInlineInstanceof(node_id, token_index, dst_type,
1606 // checking whether the assigned instance is a Smi. 1758 &done, &runtime_call);
1607 if (dst_type.IsInstantiated()) {
1608 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class());
1609 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments();
1610 // A Smi object cannot be the instance of a parameterized class.
1611 // A class equality check is only applicable with a dst type of a
1612 // non-parameterized class or with a raw dst type of a parameterized class.
1613 if (dst_class_has_type_arguments) {
1614 const AbstractTypeArguments& dst_type_arguments =
1615 AbstractTypeArguments::Handle(dst_type.arguments());
1616 const bool is_raw_dst_type = dst_type_arguments.IsNull() ||
1617 dst_type_arguments.IsRaw(dst_type_arguments.Length());
1618 if (is_raw_dst_type) {
1619 // Dynamic type argument, check only classes.
1620 if (dst_type.IsListInterface()) {
1621 // TODO(srdjan) also accept List<Object>.
1622 __ testl(EAX, Immediate(kSmiTagMask));
1623 __ j(ZERO, &runtime_call, Assembler::kNearJump);
1624 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1625 TestClassAndJump(*CoreClass("ObjectArray"), &done);
1626 TestClassAndJump(*CoreClass("GrowableObjectArray"), &done);
1627 } else if (!dst_type_class.is_interface()) {
1628 __ testl(EAX, Immediate(kSmiTagMask));
1629 __ j(ZERO, &runtime_call, Assembler::kNearJump);
1630 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1631 TestClassAndJump(dst_type_class, &done);
1632 }
1633 // Fall through to runtime class.
1634 }
1635 } else { // dst_type has NO type arguments.
1636 Label compare_classes;
1637 __ testl(EAX, Immediate(kSmiTagMask));
1638 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
1639 // Object is Smi.
1640 const Class& smi_class = Class::Handle(Smi::Class());
1641 // TODO(regis): We should introduce a SmiType.
1642 Error& malformed_error = Error::Handle();
1643 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
1644 dst_type_class,
1645 TypeArguments::Handle(),
1646 &malformed_error)) {
1647 // Successful assignable type check: return object in EAX.
1648 __ jmp(&done, Assembler::kNearJump);
1649 } else {
1650 // Failed assignable type check: call runtime to throw TypeError.
1651 __ jmp(&runtime_call, Assembler::kNearJump);
1652 }
1653 // Compare if the classes are equal.
1654 __ Bind(&compare_classes);
1655 // If dst_type is an interface, we can skip the class equality check,
1656 // because instances cannot be of an interface type.
1657 if (!dst_type_class.is_interface()) {
1658 __ LoadObject(EDX, dst_type_class);
1659 __ cmpl(EDX, ECX);
1660 __ j(EQUAL, &done, Assembler::kNearJump);
1661 // EAX, EDX are preserved in stub, result is in EBX.
1662 __ call(&StubCode::IsRawSubTypeLabel());
1663 // Result in EBX: 1 is raw subtype.
1664 __ cmpl(EBX, Immediate(1));
1665 __ j(EQUAL, &done, Assembler::kNearJump);
1666 // Otherwise fallthrough
1667 } else {
1668 // However, for specific core library interfaces, we can check for
1669 // specific core library classes.
1670 Error& malformed_error = Error::Handle();
1671 if (dst_type.IsBoolInterface()) {
1672 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1673 const Class& bool_class = Class::ZoneHandle(
1674 Isolate::Current()->object_store()->bool_class());
1675 TestClassAndJump(bool_class, &done);
1676 } else if (dst_type.IsSubtypeOf(
1677 Type::Handle(Type::NumberInterface()), &malformed_error)) {
1678 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1679 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) {
1680 // We already checked for Smi above.
1681 const Class& mint_class = Class::ZoneHandle(
1682 Isolate::Current()->object_store()->mint_class());
1683 TestClassAndJump(mint_class, &done);
1684 const Class& bigint_class = Class::ZoneHandle(
1685 Isolate::Current()->object_store()->bigint_class());
1686 TestClassAndJump(bigint_class, &done);
1687 }
1688 if (dst_type.IsDoubleInterface() || dst_type.IsNumberInterface()) {
1689 const Class& double_class = Class::ZoneHandle(
1690 Isolate::Current()->object_store()->double_class());
1691 TestClassAndJump(double_class, &done);
1692 }
1693 } else if (dst_type.IsStringInterface()) {
1694 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1695 const Class& one_byte_string_class = Class::ZoneHandle(
1696 Isolate::Current()->object_store()->one_byte_string_class());
1697 TestClassAndJump(one_byte_string_class, &done);
1698 const Class& two_byte_string_class = Class::ZoneHandle(
1699 Isolate::Current()->object_store()->two_byte_string_class());
1700 TestClassAndJump(two_byte_string_class, &done);
1701 const Class& four_byte_string_class = Class::ZoneHandle(
1702 Isolate::Current()->object_store()->four_byte_string_class());
1703 TestClassAndJump(four_byte_string_class, &done);
1704 } else if (dst_type.IsFunctionInterface()) {
1705 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1706 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset()));
1707 __ cmpl(ECX, raw_null);
1708 __ j(NOT_EQUAL, &done, Assembler::kNearJump);
1709 } else {
1710 __ LoadObject(EDX, dst_type_class);
1711 // EAX: Instance (preserved).
1712 // EDX: test class (preserved).
1713 __ call(&StubCode::IsRawSubTypeLabel());
1714 // Result in EBX: 1 is raw subtype.
1715 __ cmpl(EBX, Immediate(1));
1716 __ j(EQUAL, &done, Assembler::kNearJump);
1717 // Otherwise fallthrough
1718 }
1719 }
1720 }
1721 } else {
1722 ASSERT(!dst_type.IsInstantiated());
1723 // Skip check if destination is a dynamic type.
1724 if (dst_type.IsTypeParameter()) {
1725 // EAX must be preserved!
1726 Label fall_through;
1727 GenerateInstantiatorTypeArguments(token_index);
1728 // Type arguments are on stack
1729 __ popl(EBX);
1730 // Check if dynamic.
1731 __ cmpl(EBX, raw_null);
1732 __ j(EQUAL, &done, Assembler::kNearJump);
1733 1759
1734 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
1735 __ movl(EDX, FieldAddress(EBX, Object::class_offset()));
1736 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class()));
1737 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1738 // EBX: Instance of TypeArguments.
1739 __ movl(EDX,
1740 FieldAddress(EBX, TypeArguments::type_at_offset(dst_type.Index())));
1741 // EDX: concrete type of dst_type.
1742 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType()));
1743 __ j(EQUAL, &done, Assembler::kNearJump);
1744 // Check if the type has type parameters, if not do the class comparison.
1745 Label not_smi;
1746 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi?
1747 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
1748 __ CompareObject(EDX, Type::ZoneHandle(Type::IntInterface()));
1749 __ j(EQUAL, &done, Assembler::kNearJump);
1750 __ CompareObject(EDX, Type::ZoneHandle(Type::NumberInterface()));
1751 __ j(EQUAL, &done, Assembler::kNearJump);
1752 __ Bind(&not_smi);
1753 // The instantiated type parameter may not be a Type, but could be an
1754 // InstantiatedType. It is therefore necessary to check its class.
1755 __ movl(ECX, FieldAddress(EDX, Object::class_offset()));
1756 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class()));
1757 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1758 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset()));
1759 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset()));
1760 // Check that class of dst_type has no type parameters.
1761 __ cmpl(ECX, raw_null);
1762 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1763 // We have a non-parameterized class in EDX, compare with class of
1764 // value in EAX. EAX, EDX are preserved in stub.
1765 __ call(&StubCode::IsRawSubTypeLabel());
1766 // Result in EBX: 1 is raw subtype.
1767 __ cmpl(EBX, Immediate(1));
1768 __ j(EQUAL, &done, Assembler::kNearJump);
1769 __ Bind(&fall_through);
1770 }
1771 }
1772 __ Bind(&runtime_call); 1760 __ Bind(&runtime_call);
1773 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1761 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1774 const Immediate location = 1762 const Immediate location =
1775 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); 1763 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index)));
1764 const Immediate node_id_as_smi =
1765 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id)));
1776 __ pushl(location); // Push the source location. 1766 __ pushl(location); // Push the source location.
1767 __ pushl(node_id_as_smi); // node-id.
1777 __ pushl(EAX); // Push the source object. 1768 __ pushl(EAX); // Push the source object.
1778 __ PushObject(dst_type); // Push the type of the destination. 1769 __ PushObject(dst_type); // Push the type of the destination.
1779 if (dst_type.IsInstantiated()) { 1770 if (dst_type.IsInstantiated()) {
1780 __ pushl(raw_null); // Null instantiator. 1771 __ pushl(raw_null); // Null instantiator.
1781 } else { 1772 } else {
1782 GenerateInstantiatorTypeArguments(token_index); 1773 GenerateInstantiatorTypeArguments(token_index);
1783 } 1774 }
1784 __ PushObject(dst_name); // Push the name of the destination. 1775 __ PushObject(dst_name); // Push the name of the destination.
1785 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); 1776 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry);
1786 // Pop the parameters supplied to the runtime entry. The result of the 1777 // Pop the parameters supplied to the runtime entry. The result of the
1787 // type check runtime call is the checked value. 1778 // type check runtime call is the checked value.
1788 __ addl(ESP, Immediate(5 * kWordSize)); 1779 __ addl(ESP, Immediate(6 * kWordSize));
1789 __ popl(EAX); 1780 __ popl(EAX);
1790 1781
1791 // EAX: value. 1782 // EAX: value.
1792 __ Bind(&done); 1783 __ Bind(&done);
1793 } 1784 }
1794 1785
1795 1786
1796 void CodeGenerator::GenerateArgumentTypeChecks() { 1787 void CodeGenerator::GenerateArgumentTypeChecks() {
1797 const Function& function = parsed_function_.function(); 1788 const Function& function = parsed_function_.function();
1798 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); 1789 const SequenceNode& sequence_node = *parsed_function_.node_sequence();
(...skipping 1093 matching lines...) Expand 10 before | Expand all | Expand 10 after
2892 const Error& error = Error::Handle( 2883 const Error& error = Error::Handle(
2893 Parser::FormatError(script, token_index, "Error", format, args)); 2884 Parser::FormatError(script, token_index, "Error", format, args));
2894 va_end(args); 2885 va_end(args);
2895 Isolate::Current()->long_jump_base()->Jump(1, error); 2886 Isolate::Current()->long_jump_base()->Jump(1, error);
2896 UNREACHABLE(); 2887 UNREACHABLE();
2897 } 2888 }
2898 2889
2899 } // namespace dart 2890 } // namespace dart
2900 2891
2901 #endif // defined TARGET_ARCH_IA32 2892 #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