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

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

Issue 10128009: Reverting CL 6764. (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
1347 // If instanceof type test cannot be performed successfully at compile time and 1288 // If instanceof type test cannot be performed successfully at compile time and
1348 // therefore eliminated, optimize it by adding inlined tests for: 1289 // therefore eliminated, optimize it by adding inlined tests for:
1349 // - NULL -> return false. 1290 // - NULL -> return false.
1350 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1291 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1351 // - Class equality (only if class is not parameterized). 1292 // - Class equality (only if class is not parameterized).
1352 // Inputs: 1293 // Inputs:
1353 // - EAX: object. 1294 // - EAX: object.
1354 // Destroys ECX. 1295 // Destroys ECX.
1355 // Returns: 1296 // Returns:
1356 // - true or false on stack. 1297 // - true or false on stack.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1393 &malformed_error)) { 1334 &malformed_error)) {
1394 __ PushObject(negate_result ? bool_false : bool_true); 1335 __ PushObject(negate_result ? bool_false : bool_true);
1395 } else { 1336 } else {
1396 ASSERT(malformed_error.IsNull()); 1337 ASSERT(malformed_error.IsNull());
1397 __ PushObject(negate_result ? bool_true : bool_false); 1338 __ PushObject(negate_result ? bool_true : bool_false);
1398 } 1339 }
1399 } 1340 }
1400 return; 1341 return;
1401 } 1342 }
1402 1343
1403 Label is_instance_of, is_not_instance_of;
1404 const Immediate raw_null = 1344 const Immediate raw_null =
1405 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1345 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1406 Label done; 1346 Label done, check_negate_done;
1407 // If type is instantiated and non-parameterized, we can inline code 1347 // If type is instantiated and non-parameterized, we can inline code
1408 // checking whether the tested instance is a Smi. 1348 // checking whether the tested instance is a Smi.
1409 if (type.IsInstantiated()) { 1349 if (type.IsInstantiated()) {
1410 // A null object is only an instance of Object and Dynamic, which has 1350 // A null object is only an instance of Object and Dynamic, which has
1411 // already been checked above (if the type is instantiated). So we can 1351 // already been checked above (if the type is instantiated). So we can
1412 // return false here if the instance is null (and if the type is 1352 // return false here if the instance is null (and if the type is
1413 // instantiated). 1353 // instantiated).
1414 // We can only inline this null check if the type is instantiated at compile 1354 // We can only inline this null check if the type is instantiated at compile
1415 // time, since an uninstantiated type at compile time could be Object or 1355 // time, since an uninstantiated type at compile time could be Object or
1416 // Dynamic at run time. 1356 // Dynamic at run time.
1417 Label non_null; 1357 Label non_null;
1418 __ cmpl(EAX, raw_null); 1358 __ cmpl(EAX, raw_null);
1419 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); 1359 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump);
1420 __ PushObject(negate_result ? bool_true : bool_false); 1360 __ PushObject(negate_result ? bool_true : bool_false);
1421 __ jmp(&done); 1361 __ jmp(&done, Assembler::kNearJump);
1362
1422 __ Bind(&non_null); 1363 __ Bind(&non_null);
1364
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 }
1423 } 1477 }
1424
1425 GenerateInlineInstanceof(node_id, token_index, type,
1426 &is_instance_of, &is_not_instance_of);
1427
1428 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1478 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1429 const Immediate location = 1479 const Immediate location =
1430 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); 1480 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index)));
1431 const Immediate node_id_as_smi = 1481 const Immediate node_id_as_smi =
1432 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id))); 1482 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id)));
1433 __ pushl(location); // Push the source location. 1483 __ pushl(location); // Push the source location.
1434 __ pushl(node_id_as_smi); // node-id. 1484 __ pushl(node_id_as_smi); // node-id.
1435 __ pushl(EAX); // Push the instance. 1485 __ pushl(EAX); // Push the instance.
1436 __ PushObject(type); // Push the type. 1486 __ PushObject(type); // Push the type.
1437 if (!type.IsInstantiated()) { 1487 if (!type.IsInstantiated()) {
1438 GenerateInstantiatorTypeArguments(token_index); 1488 GenerateInstantiatorTypeArguments(token_index);
1439 } else { 1489 } else {
1440 __ pushl(raw_null); // Null instantiator. 1490 __ pushl(raw_null); // Null instantiator.
1441 } 1491 }
1442 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); 1492 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry);
1443 // Pop the two parameters supplied to the runtime entry. The result of the 1493 // Pop the two parameters supplied to the runtime entry. The result of the
1444 // instanceof runtime call will be left as the result of the operation. 1494 // instanceof runtime call will be left as the result of the operation.
1445 __ addl(ESP, Immediate(5 * kWordSize)); 1495 __ addl(ESP, Immediate(5 * kWordSize));
1446 __ jmp(&done); 1496 __ Bind(&check_negate_done);
1447 1497 if (negate_result) {
1448 __ Bind(&is_instance_of); 1498 Label negate_done;
1449 __ PushObject(negate_result ? bool_false: bool_true); 1499 __ popl(EDX);
1450 __ jmp(&done); 1500 __ LoadObject(EAX, bool_true);
1451 __ Bind(&is_not_instance_of); 1501 __ cmpl(EDX, EAX);
1452 __ PushObject(negate_result ? bool_true: bool_false); 1502 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump);
1503 __ LoadObject(EAX, bool_false);
1504 __ Bind(&negate_done);
1505 __ pushl(EAX);
1506 }
1453 __ Bind(&done); 1507 __ Bind(&done);
1454 } 1508 }
1455 1509
1456 1510
1457 // EAX: instance to test. 1511 // Jumps to label if ECX equals the given class.
1458 // Clobbers: ECX. 1512 // Inputs:
1459 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if 1513 // - ECX: tested class.
1460 // type test is conclusive, otherwise fallthrough if a type test could not 1514 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) {
1461 // be completed. 1515 __ CompareObject(ECX, cls);
1462 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( 1516 __ j(EQUAL, label, Assembler::kNearJump);
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 }
1660 } 1517 }
1661 1518
1662 1519
1663 // If type check cannot be performed successfully at compile time and therefore 1520 // If type check cannot be performed successfully at compile time and therefore
1664 // eliminated, optimize it by adding inlined tests for: 1521 // eliminated, optimize it by adding inlined tests for:
1665 // - NULL -> return NULL. 1522 // - NULL -> return NULL.
1666 // - Smi -> compile time subtype check (only if dst class is not parameterized). 1523 // - Smi -> compile time subtype check (only if dst class is not parameterized).
1667 // - Class equality (only if class is not parameterized). 1524 // - Class equality (only if class is not parameterized).
1668 // Inputs: 1525 // Inputs:
1669 // - EAX: object. 1526 // - EAX: object.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1738 __ PushObject(dst_name); // Push the name of the destination. 1595 __ PushObject(dst_name); // Push the name of the destination.
1739 __ PushObject(error_message); 1596 __ PushObject(error_message);
1740 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); 1597 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry);
1741 // We should never return here. 1598 // We should never return here.
1742 __ int3(); 1599 __ int3();
1743 1600
1744 __ Bind(&done); // For a null object. 1601 __ Bind(&done); // For a null object.
1745 return; 1602 return;
1746 } 1603 }
1747 1604
1748 GenerateInlineInstanceof(node_id, token_index, dst_type, 1605 // If dst_type is instantiated and non-parameterized, we can inline code
1749 &done, &runtime_call); 1606 // checking whether the assigned instance is a Smi.
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);
1750 1733
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 }
1751 __ Bind(&runtime_call); 1772 __ Bind(&runtime_call);
1752 __ PushObject(Object::ZoneHandle()); // Make room for the result. 1773 __ PushObject(Object::ZoneHandle()); // Make room for the result.
1753 const Immediate location = 1774 const Immediate location =
1754 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); 1775 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)));
1757 __ pushl(location); // Push the source location. 1776 __ pushl(location); // Push the source location.
1758 __ pushl(node_id_as_smi); // node-id.
1759 __ pushl(EAX); // Push the source object. 1777 __ pushl(EAX); // Push the source object.
1760 __ PushObject(dst_type); // Push the type of the destination. 1778 __ PushObject(dst_type); // Push the type of the destination.
1761 if (dst_type.IsInstantiated()) { 1779 if (dst_type.IsInstantiated()) {
1762 __ pushl(raw_null); // Null instantiator. 1780 __ pushl(raw_null); // Null instantiator.
1763 } else { 1781 } else {
1764 GenerateInstantiatorTypeArguments(token_index); 1782 GenerateInstantiatorTypeArguments(token_index);
1765 } 1783 }
1766 __ PushObject(dst_name); // Push the name of the destination. 1784 __ PushObject(dst_name); // Push the name of the destination.
1767 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); 1785 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry);
1768 // Pop the parameters supplied to the runtime entry. The result of the 1786 // Pop the parameters supplied to the runtime entry. The result of the
1769 // type check runtime call is the checked value. 1787 // type check runtime call is the checked value.
1770 __ addl(ESP, Immediate(6 * kWordSize)); 1788 __ addl(ESP, Immediate(5 * kWordSize));
1771 __ popl(EAX); 1789 __ popl(EAX);
1772 1790
1773 // EAX: value. 1791 // EAX: value.
1774 __ Bind(&done); 1792 __ Bind(&done);
1775 } 1793 }
1776 1794
1777 1795
1778 void CodeGenerator::GenerateArgumentTypeChecks() { 1796 void CodeGenerator::GenerateArgumentTypeChecks() {
1779 const Function& function = parsed_function_.function(); 1797 const Function& function = parsed_function_.function();
1780 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); 1798 const SequenceNode& sequence_node = *parsed_function_.node_sequence();
(...skipping 1093 matching lines...) Expand 10 before | Expand all | Expand 10 after
2874 const Error& error = Error::Handle( 2892 const Error& error = Error::Handle(
2875 Parser::FormatError(script, token_index, "Error", format, args)); 2893 Parser::FormatError(script, token_index, "Error", format, args));
2876 va_end(args); 2894 va_end(args);
2877 Isolate::Current()->long_jump_base()->Jump(1, error); 2895 Isolate::Current()->long_jump_base()->Jump(1, error);
2878 UNREACHABLE(); 2896 UNREACHABLE();
2879 } 2897 }
2880 2898
2881 } // namespace dart 2899 } // namespace dart
2882 2900
2883 #endif // defined TARGET_ARCH_IA32 2901 #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