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

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 // EAX: instance to test.
1512 // Inputs: 1458 // Clobbers: ECX.
1513 // - ECX: tested class. 1459 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
1514 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { 1460 // type test is conclusive, otherwise fallthrough if a type test could not
1515 __ CompareObject(ECX, cls); 1461 // be completed.
1516 __ j(EQUAL, label, Assembler::kNearJump); 1462 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest(
1463 const AbstractType& type,
1464 Label* is_instance_lbl,
1465 Label* is_not_instance_lbl) {
1466 ASSERT(type.IsInstantiated());
1467 const Class& type_class = Class::ZoneHandle(type.type_class());
1468 ASSERT(type_class.HasTypeArguments());
1469 // A Smi object cannot be the instance of a parameterized class.
1470 // A class equality check is only applicable with a dst type of a
1471 // non-parameterized class or with a raw dst type of a parameterized class.
1472 __ testl(EAX, Immediate(kSmiTagMask));
1473 __ j(ZERO, is_not_instance_lbl);
1474 const AbstractTypeArguments& type_arguments =
1475 AbstractTypeArguments::Handle(type.arguments());
1476 const bool is_raw_type = type_arguments.IsNull() ||
1477 type_arguments.IsRaw(type_arguments.Length());
1478 if (is_raw_type) {
1479 // Dynamic type argument, check only classes.
1480 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1481 if (type.IsListInterface()) {
1482 // TODO(srdjan) also accept List<Object>.
1483 __ CompareObject(ECX, *CoreClass("ObjectArray"));
1484 __ j(EQUAL, is_instance_lbl);
1485 __ CompareObject(ECX, *CoreClass("GrowableObjectArray"));
1486 __ j(EQUAL, is_instance_lbl);
1487 } else if (!type_class.is_interface()) {
1488 __ CompareObject(ECX, type_class);
1489 __ j(EQUAL, is_instance_lbl);
1490 }
1491 } else {
1492 // TODO(srdjan): do type test on type arguments.
1493 }
1494 // Fall through if type test is not conclusive
1495 }
1496
1497
1498 // EAX: instance to test.
1499 // Clobbers: EBX, ECX, EDX.
1500 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest(
1501 intptr_t node_id,
1502 intptr_t token_index,
1503 const AbstractType& type,
1504 Label* is_instance_lbl,
1505 Label* is_not_instance_lbl) {
1506 ASSERT(type.IsInstantiated());
1507 const Class& type_class = Class::ZoneHandle(type.type_class());
1508 ASSERT(!type_class.HasTypeArguments());
1509
1510 Label compare_classes;
1511 __ testl(EAX, Immediate(kSmiTagMask));
1512 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
1513 // Instance is Smi, check directly.
1514 const Class& smi_class = Class::Handle(Smi::Class());
1515 // TODO(regis): We should introduce a SmiType.
1516 Error& malformed_error = Error::Handle();
1517 if (smi_class.IsSubtypeOf(TypeArguments::Handle(),
1518 type_class,
1519 TypeArguments::Handle(),
1520 &malformed_error)) {
1521 __ jmp(is_instance_lbl);
1522 } else {
1523 __ jmp(is_not_instance_lbl);
1524 }
1525 // Compare if the classes are equal.
1526 __ Bind(&compare_classes);
1527
1528 // Checking against interface.
1529 // However, for specific core library interfaces, we can check for
1530 // specific core library classes.
1531 if (type.IsBoolInterface()) {
1532 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1533 const Class& bool_class = Class::ZoneHandle(
1534 Isolate::Current()->object_store()->bool_class());
1535 __ CompareObject(ECX, bool_class);
1536 __ j(EQUAL, is_instance_lbl);
1537 return;
1538 }
1539 // If type is an interface, we can skip the class equality check,
1540 // because instances cannot be of an interface type.
1541 if (!type_class.is_interface()) {
1542 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1543 __ CompareObject(ECX, type_class);
1544 __ j(EQUAL, is_instance_lbl);
1545 }
1546 if (type.IsSubtypeOf(
1547 Type::Handle(Type::NumberInterface()), &malformed_error)) {
1548 // Custom checking for numbers (Smi, Mint, Bigint and Double)
1549 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1550 if (type.IsIntInterface() || type.IsNumberInterface()) {
1551 // We already checked for Smi above.
1552 const Class& mint_class = Class::ZoneHandle(
1553 Isolate::Current()->object_store()->mint_class());
1554 const Class& bigint_class = Class::ZoneHandle(
1555 Isolate::Current()->object_store()->bigint_class());
1556 __ CompareObject(ECX, mint_class);
1557 __ j(EQUAL, is_instance_lbl);
1558 __ CompareObject(ECX, bigint_class);
1559 __ j(EQUAL, is_instance_lbl);
1560 }
1561 if (type.IsDoubleInterface() || type.IsNumberInterface()) {
1562 const Class& double_class = Class::ZoneHandle(
1563 Isolate::Current()->object_store()->double_class());
1564 __ CompareObject(ECX, double_class);
1565 __ j(EQUAL, is_instance_lbl);
1566 }
1567 } else if (type.IsStringInterface()) {
1568 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1569 const Class& one_byte_string_class = Class::ZoneHandle(
1570 Isolate::Current()->object_store()->one_byte_string_class());
1571 const Class& two_byte_string_class = Class::ZoneHandle(
1572 Isolate::Current()->object_store()->two_byte_string_class());
1573 const Class& four_byte_string_class = Class::ZoneHandle(
1574 Isolate::Current()->object_store()->four_byte_string_class());
1575 __ CompareObject(ECX, one_byte_string_class);
1576 __ j(EQUAL, is_instance_lbl);
1577 __ CompareObject(ECX, two_byte_string_class);
1578 __ j(EQUAL, is_instance_lbl);
1579 __ CompareObject(ECX, four_byte_string_class);
1580 __ j(EQUAL, is_instance_lbl);
1581 } else if (type.IsFunctionInterface()) {
1582 // Check if instance is a closure.
1583 const Immediate raw_null =
1584 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1585 __ movl(ECX, FieldAddress(EAX, Object::class_offset()));
1586 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset()));
1587 __ cmpl(ECX, raw_null);
1588 __ j(NOT_EQUAL, is_instance_lbl);
1589 }
1590 // Otherwise fallthrough.
1591 }
1592
1593
1594 // EAX: instance to test.
1595 // Clobbers: EBX, EDX, ECX.
1596 void CodeGenerator::GenerateUninstantiatedTypeTest(
1597 const AbstractType& type,
1598 intptr_t token_index,
1599 Label* is_instance_lbl) {
1600 ASSERT(!type.IsInstantiated());
1601 // Skip check if destination is a dynamic type.
1602 if (type.IsTypeParameter()) {
1603 const Immediate raw_null =
1604 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1605 // EAX must be preserved!
1606 Label fall_through;
1607 GenerateInstantiatorTypeArguments(token_index);
1608 // Type arguments are on stack.
1609 __ popl(EBX);
1610 // Check if type argument is dynamic.
1611 __ cmpl(EBX, raw_null);
1612 __ j(EQUAL, is_instance_lbl);
1613
1614 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs.
1615 __ movl(EDX, FieldAddress(EBX, Object::class_offset()));
1616 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class()));
1617 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1618
1619 // EBX: Instance of TypeArguments.
1620 __ movl(EDX,
1621 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index())));
1622 // EDX: concrete type of type.
1623 // Check if type argument is dynamic.
1624 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType()));
1625 __ j(EQUAL, is_instance_lbl);
1626
1627 // Check if the type has type parameters, if not do the class comparison.
1628 Label not_smi;
1629 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi?
1630 __ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
1631 // For Smi check quickly against int and num interfaces.
1632 __ CompareObject(EDX, Type::ZoneHandle(Type::IntInterface()));
1633 __ j(EQUAL, is_instance_lbl);
1634 __ CompareObject(EDX, Type::ZoneHandle(Type::NumberInterface()));
1635 __ j(EQUAL, is_instance_lbl);
1636 __ jmp(&fall_through);
1637
1638 __ Bind(&not_smi);
1639 // The instantiated type parameter may not be a Type, but could be an
1640 // InstantiatedType. It is therefore necessary to check its class.
1641 __ movl(ECX, FieldAddress(EDX, Object::class_offset()));
1642 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class()));
1643 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1644
1645 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset()));
1646 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset()));
1647 // Check that class of type has no type parameters.
1648 __ cmpl(ECX, raw_null);
1649 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
1650 // We have a non-parameterized class in EDX, compare with class of
1651 // value in EAX. EAX, EDX are preserved in stub.
1652 __ call(&StubCode::IsRawSubTypeLabel());
1653 // Result in EBX: 1 is raw subtype.
1654 __ cmpl(EBX, Immediate(1));
1655 __ j(EQUAL, is_instance_lbl);
1656
1657 // Test not conclusive.
1658 __ Bind(&fall_through);
1659 }
1517 } 1660 }
1518 1661
1519 1662
1520 // If type check cannot be performed successfully at compile time and therefore 1663 // If type check cannot be performed successfully at compile time and therefore
1521 // eliminated, optimize it by adding inlined tests for: 1664 // eliminated, optimize it by adding inlined tests for:
1522 // - NULL -> return NULL. 1665 // - NULL -> return NULL.
1523 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1666 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1524 // - Class equality (only if class is not parameterized). 1667 // - Class equality (only if class is not parameterized).
1525 // Inputs: 1668 // Inputs:
1526 // - EAX: object. 1669 // - EAX: object.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1595 __ PushObject(dst_name); // Push the name of the destination. 1738 __ PushObject(dst_name); // Push the name of the destination.
1596 __ PushObject(error_message); 1739 __ PushObject(error_message);
1597 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); 1740 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry);
1598 // We should never return here. 1741 // We should never return here.
1599 __ int3(); 1742 __ int3();
1600 1743
1601 __ Bind(&done); // For a null object. 1744 __ Bind(&done); // For a null object.
1602 return; 1745 return;
1603 } 1746 }
1604 1747
1605 // If dst_type is instantiated and non-parameterized, we can inline code 1748 GenerateInlineInstanceof(node_id, token_index, dst_type,
1606 // checking whether the assigned instance is a Smi. 1749 &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 1750
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); 1751 __ Bind(&runtime_call);
1773 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1752 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1774 const Immediate location = 1753 const Immediate location =
1775 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); 1754 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index)));
1755 const Immediate node_id_as_smi =
1756 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id)));
1776 __ pushl(location); // Push the source location. 1757 __ pushl(location); // Push the source location.
1758 __ pushl(node_id_as_smi); // node-id.
1777 __ pushl(EAX); // Push the source object. 1759 __ pushl(EAX); // Push the source object.
1778 __ PushObject(dst_type); // Push the type of the destination. 1760 __ PushObject(dst_type); // Push the type of the destination.
1779 if (dst_type.IsInstantiated()) { 1761 if (dst_type.IsInstantiated()) {
1780 __ pushl(raw_null); // Null instantiator. 1762 __ pushl(raw_null); // Null instantiator.
1781 } else { 1763 } else {
1782 GenerateInstantiatorTypeArguments(token_index); 1764 GenerateInstantiatorTypeArguments(token_index);
1783 } 1765 }
1784 __ PushObject(dst_name); // Push the name of the destination. 1766 __ PushObject(dst_name); // Push the name of the destination.
1785 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); 1767 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry);
1786 // Pop the parameters supplied to the runtime entry. The result of the 1768 // Pop the parameters supplied to the runtime entry. The result of the
1787 // type check runtime call is the checked value. 1769 // type check runtime call is the checked value.
1788 __ addl(ESP, Immediate(5 * kWordSize)); 1770 __ addl(ESP, Immediate(6 * kWordSize));
1789 __ popl(EAX); 1771 __ popl(EAX);
1790 1772
1791 // EAX: value. 1773 // EAX: value.
1792 __ Bind(&done); 1774 __ Bind(&done);
1793 } 1775 }
1794 1776
1795 1777
1796 void CodeGenerator::GenerateArgumentTypeChecks() { 1778 void CodeGenerator::GenerateArgumentTypeChecks() {
1797 const Function& function = parsed_function_.function(); 1779 const Function& function = parsed_function_.function();
1798 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); 1780 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( 2874 const Error& error = Error::Handle(
2893 Parser::FormatError(script, token_index, "Error", format, args)); 2875 Parser::FormatError(script, token_index, "Error", format, args));
2894 va_end(args); 2876 va_end(args);
2895 Isolate::Current()->long_jump_base()->Jump(1, error); 2877 Isolate::Current()->long_jump_base()->Jump(1, error);
2896 UNREACHABLE(); 2878 UNREACHABLE();
2897 } 2879 }
2898 2880
2899 } // namespace dart 2881 } // namespace dart
2900 2882
2901 #endif // defined TARGET_ARCH_IA32 2883 #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