| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 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 1284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1295 intptr_t token_index, | 1295 intptr_t token_index, |
| 1296 const AbstractType& type, | 1296 const AbstractType& type, |
| 1297 bool negate_result) { | 1297 bool negate_result) { |
| 1298 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 1298 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1299 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1299 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1300 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1300 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1301 | 1301 |
| 1302 // All instances are of a subtype of the Object type. | 1302 // All instances are of a subtype of the Object type. |
| 1303 const Type& object_type = | 1303 const Type& object_type = |
| 1304 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1304 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1305 if (type.IsInstantiated() && object_type.IsSubtypeOf(type)) { | 1305 Error& malformed_error = Error::Handle(); |
| 1306 if (type.IsInstantiated() && |
| 1307 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1306 __ PushObject(negate_result ? bool_false : bool_true); | 1308 __ PushObject(negate_result ? bool_false : bool_true); |
| 1307 return; | 1309 return; |
| 1308 } | 1310 } |
| 1309 | 1311 |
| 1310 const Immediate raw_null = | 1312 const Immediate raw_null = |
| 1311 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1313 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1312 Label done; | 1314 Label done; |
| 1313 // If type is instantiated and non-parameterized, we can inline code | 1315 // If type is instantiated and non-parameterized, we can inline code |
| 1314 // checking whether the tested instance is a Smi. | 1316 // checking whether the tested instance is a Smi. |
| 1315 if (type.IsInstantiated()) { | 1317 if (type.IsInstantiated()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1364 } | 1366 } |
| 1365 __ Bind(&runtime_call); | 1367 __ Bind(&runtime_call); |
| 1366 // Fall through to runtime call. | 1368 // Fall through to runtime call. |
| 1367 } else { | 1369 } else { |
| 1368 Label compare_classes; | 1370 Label compare_classes; |
| 1369 __ testq(RAX, Immediate(kSmiTagMask)); | 1371 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1370 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1372 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1371 // Object is Smi. | 1373 // Object is Smi. |
| 1372 const Class& smi_class = Class::Handle(Smi::Class()); | 1374 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1373 // TODO(regis): We should introduce a SmiType. | 1375 // TODO(regis): We should introduce a SmiType. |
| 1376 Error& malformed_error = Error::Handle(); |
| 1374 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1377 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1375 type_class, | 1378 type_class, |
| 1376 TypeArguments::Handle())) { | 1379 TypeArguments::Handle(), |
| 1380 &malformed_error)) { |
| 1377 __ PushObject(negate_result ? bool_false : bool_true); | 1381 __ PushObject(negate_result ? bool_false : bool_true); |
| 1378 } else { | 1382 } else { |
| 1379 __ PushObject(negate_result ? bool_true : bool_false); | 1383 __ PushObject(negate_result ? bool_true : bool_false); |
| 1380 } | 1384 } |
| 1381 __ jmp(&done); | 1385 __ jmp(&done); |
| 1382 | 1386 |
| 1383 // Compare if the classes are equal. | 1387 // Compare if the classes are equal. |
| 1384 __ Bind(&compare_classes); | 1388 __ Bind(&compare_classes); |
| 1385 const Class* compare_class = NULL; | 1389 const Class* compare_class = NULL; |
| 1386 if (type.IsStringInterface()) { | 1390 if (type.IsStringInterface()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1397 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1401 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1398 __ CompareObject(RCX, *compare_class); | 1402 __ CompareObject(RCX, *compare_class); |
| 1399 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1403 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1400 __ PushObject(negate_result ? bool_false : bool_true); | 1404 __ PushObject(negate_result ? bool_false : bool_true); |
| 1401 __ jmp(&done, Assembler::kNearJump); | 1405 __ jmp(&done, Assembler::kNearJump); |
| 1402 __ Bind(&runtime_call); | 1406 __ Bind(&runtime_call); |
| 1403 } | 1407 } |
| 1404 } | 1408 } |
| 1405 } | 1409 } |
| 1406 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1410 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1411 const Immediate location = |
| 1412 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); |
| 1413 __ pushq(location); // Push the source location. |
| 1407 __ pushq(RAX); // Push the instance. | 1414 __ pushq(RAX); // Push the instance. |
| 1408 __ PushObject(type); // Push the type. | 1415 __ PushObject(type); // Push the type. |
| 1409 if (!type.IsInstantiated()) { | 1416 if (!type.IsInstantiated()) { |
| 1410 GenerateInstantiatorTypeArguments(token_index); | 1417 GenerateInstantiatorTypeArguments(token_index); |
| 1411 } else { | 1418 } else { |
| 1412 __ pushq(raw_null); // Null instantiator. | 1419 __ pushq(raw_null); // Null instantiator. |
| 1413 } | 1420 } |
| 1414 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1421 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1415 // Pop the two parameters supplied to the runtime entry. The result of the | 1422 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1416 // instanceof runtime call will be left as the result of the operation. | 1423 // instanceof runtime call will be left as the result of the operation. |
| 1417 __ addq(RSP, Immediate(3 * kWordSize)); | 1424 __ addq(RSP, Immediate(4 * kWordSize)); |
| 1418 if (negate_result) { | 1425 if (negate_result) { |
| 1419 Label negate_done; | 1426 Label negate_done; |
| 1420 __ popq(RDX); | 1427 __ popq(RDX); |
| 1421 __ LoadObject(RAX, bool_true); | 1428 __ LoadObject(RAX, bool_true); |
| 1422 __ cmpq(RDX, RAX); | 1429 __ cmpq(RDX, RAX); |
| 1423 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1430 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 1424 __ LoadObject(RAX, bool_false); | 1431 __ LoadObject(RAX, bool_false); |
| 1425 __ Bind(&negate_done); | 1432 __ Bind(&negate_done); |
| 1426 __ pushq(RAX); | 1433 __ pushq(RAX); |
| 1427 } | 1434 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1449 // - object in RAX for successful assignable check (or throws TypeError). | 1456 // - object in RAX for successful assignable check (or throws TypeError). |
| 1450 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1457 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1451 intptr_t token_index, | 1458 intptr_t token_index, |
| 1452 const AbstractType& dst_type, | 1459 const AbstractType& dst_type, |
| 1453 const String& dst_name) { | 1460 const String& dst_name) { |
| 1454 ASSERT(FLAG_enable_type_checks); | 1461 ASSERT(FLAG_enable_type_checks); |
| 1455 ASSERT(token_index >= 0); | 1462 ASSERT(token_index >= 0); |
| 1456 ASSERT(!dst_type.IsNull()); | 1463 ASSERT(!dst_type.IsNull()); |
| 1457 ASSERT(dst_type.IsFinalized()); | 1464 ASSERT(dst_type.IsFinalized()); |
| 1458 | 1465 |
| 1459 // Generate throw new TypeError() if the type is malformed. | |
| 1460 if (dst_type.IsMalformed()) { | |
| 1461 const Error& error = Error::Handle(dst_type.malformed_error()); | |
| 1462 const String& error_message = String::ZoneHandle( | |
| 1463 String::NewSymbol(error.ToErrorCString())); | |
| 1464 __ PushObject(Object::ZoneHandle()); // Make room for the result. | |
| 1465 const Immediate location = | |
| 1466 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); | |
| 1467 __ pushq(location); // Push the source location. | |
| 1468 __ pushq(RAX); // Push the source object. | |
| 1469 __ PushObject(error_message); | |
| 1470 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | |
| 1471 // We should never return here. | |
| 1472 __ int3(); | |
| 1473 return; | |
| 1474 } | |
| 1475 | |
| 1476 // Any expression is assignable to the Dynamic type and to the Object type. | 1466 // Any expression is assignable to the Dynamic type and to the Object type. |
| 1477 // Skip the test. | 1467 // Skip the test. |
| 1478 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { | 1468 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 1479 return; | 1469 return; |
| 1480 } | 1470 } |
| 1481 | 1471 |
| 1482 // It is a compile-time error to explicitly return a value (including null) | 1472 // It is a compile-time error to explicitly return a value (including null) |
| 1483 // from a void function. However, functions that do not explicitly return a | 1473 // from a void function. However, functions that do not explicitly return a |
| 1484 // value, implicitly return null. This includes void functions. Therefore, we | 1474 // value, implicitly return null. This includes void functions. Therefore, we |
| 1485 // skip the type test here and trust the parser to only return null in void | 1475 // skip the type test here and trust the parser to only return null in void |
| 1486 // function. | 1476 // function. |
| 1487 if (dst_type.IsVoidType()) { | 1477 if (dst_type.IsVoidType()) { |
| 1488 return; | 1478 return; |
| 1489 } | 1479 } |
| 1490 | 1480 |
| 1491 // A NULL object is always assignable and is returned as result. | 1481 // A null object is always assignable and is returned as result. |
| 1492 const Immediate raw_null = | 1482 const Immediate raw_null = |
| 1493 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1483 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1494 Label done, runtime_call; | 1484 Label done, runtime_call; |
| 1495 __ cmpq(RAX, raw_null); | 1485 __ cmpq(RAX, raw_null); |
| 1496 __ j(EQUAL, &done); | 1486 __ j(EQUAL, &done); |
| 1497 | 1487 |
| 1488 // Generate throw new TypeError() if the type is malformed. |
| 1489 if (dst_type.IsMalformed()) { |
| 1490 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 1491 const String& error_message = String::ZoneHandle( |
| 1492 String::NewSymbol(error.ToErrorCString())); |
| 1493 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1494 const Immediate location = |
| 1495 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); |
| 1496 __ pushq(location); // Push the source location. |
| 1497 __ pushq(RAX); // Push the source object. |
| 1498 __ PushObject(dst_name); // Push the name of the destination. |
| 1499 __ PushObject(error_message); |
| 1500 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1501 // We should never return here. |
| 1502 __ int3(); |
| 1503 return; |
| 1504 } |
| 1505 |
| 1498 // If dst_type is instantiated and non-parameterized, we can inline code | 1506 // If dst_type is instantiated and non-parameterized, we can inline code |
| 1499 // checking whether the assigned instance is a Smi. | 1507 // checking whether the assigned instance is a Smi. |
| 1500 if (dst_type.IsInstantiated()) { | 1508 if (dst_type.IsInstantiated()) { |
| 1501 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); | 1509 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); |
| 1502 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); | 1510 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); |
| 1503 // A Smi object cannot be the instance of a parameterized class. | 1511 // A Smi object cannot be the instance of a parameterized class. |
| 1504 // A class equality check is only applicable with a dst type of a | 1512 // A class equality check is only applicable with a dst type of a |
| 1505 // non-parameterized class or with a raw dst type of a parameterized class. | 1513 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1506 if (dst_class_has_type_arguments) { | 1514 if (dst_class_has_type_arguments) { |
| 1507 const AbstractTypeArguments& dst_type_arguments = | 1515 const AbstractTypeArguments& dst_type_arguments = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1525 } | 1533 } |
| 1526 // Fall through to runtime class. | 1534 // Fall through to runtime class. |
| 1527 } | 1535 } |
| 1528 } else { // dst_type has NO type arguments. | 1536 } else { // dst_type has NO type arguments. |
| 1529 Label compare_classes; | 1537 Label compare_classes; |
| 1530 __ testq(RAX, Immediate(kSmiTagMask)); | 1538 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1531 __ j(NOT_ZERO, &compare_classes); | 1539 __ j(NOT_ZERO, &compare_classes); |
| 1532 // Object is Smi. | 1540 // Object is Smi. |
| 1533 const Class& smi_class = Class::Handle(Smi::Class()); | 1541 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1534 // TODO(regis): We should introduce a SmiType. | 1542 // TODO(regis): We should introduce a SmiType. |
| 1543 Error& malformed_error = Error::Handle(); |
| 1535 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1544 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1536 dst_type_class, | 1545 dst_type_class, |
| 1537 TypeArguments::Handle())) { | 1546 TypeArguments::Handle(), |
| 1547 &malformed_error)) { |
| 1538 // Successful assignable type check: return object in RAX. | 1548 // Successful assignable type check: return object in RAX. |
| 1539 __ jmp(&done); | 1549 __ jmp(&done); |
| 1540 } else { | 1550 } else { |
| 1541 // Failed assignable type check: call runtime to throw TypeError. | 1551 // Failed assignable type check: call runtime to throw TypeError. |
| 1542 __ jmp(&runtime_call); | 1552 __ jmp(&runtime_call); |
| 1543 } | 1553 } |
| 1544 // Compare if the classes are equal. | 1554 // Compare if the classes are equal. |
| 1545 __ Bind(&compare_classes); | 1555 __ Bind(&compare_classes); |
| 1546 // If dst_type is an interface, we can skip the class equality check, | 1556 // If dst_type is an interface, we can skip the class equality check, |
| 1547 // because instances cannot be of an interface type. | 1557 // because instances cannot be of an interface type. |
| 1548 if (!dst_type_class.is_interface()) { | 1558 if (!dst_type_class.is_interface()) { |
| 1549 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1559 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1550 TestClassAndJump(dst_type_class, &done); | 1560 TestClassAndJump(dst_type_class, &done); |
| 1551 } else { | 1561 } else { |
| 1552 // However, for specific core library interfaces, we can check for | 1562 // However, for specific core library interfaces, we can check for |
| 1553 // specific core library classes. | 1563 // specific core library classes. |
| 1564 Error& malformed_error = Error::Handle(); |
| 1554 if (dst_type.IsBoolInterface()) { | 1565 if (dst_type.IsBoolInterface()) { |
| 1555 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1566 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1556 const Class& bool_class = Class::ZoneHandle( | 1567 const Class& bool_class = Class::ZoneHandle( |
| 1557 Isolate::Current()->object_store()->bool_class()); | 1568 Isolate::Current()->object_store()->bool_class()); |
| 1558 TestClassAndJump(bool_class, &done); | 1569 TestClassAndJump(bool_class, &done); |
| 1559 } else if (dst_type.IsSubtypeOf( | 1570 } else if (dst_type.IsSubtypeOf( |
| 1560 Type::Handle(Type::NumberInterface()))) { | 1571 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1561 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1572 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1562 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { | 1573 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { |
| 1563 // We already checked for Smi above. | 1574 // We already checked for Smi above. |
| 1564 const Class& mint_class = Class::ZoneHandle( | 1575 const Class& mint_class = Class::ZoneHandle( |
| 1565 Isolate::Current()->object_store()->mint_class()); | 1576 Isolate::Current()->object_store()->mint_class()); |
| 1566 TestClassAndJump(mint_class, &done); | 1577 TestClassAndJump(mint_class, &done); |
| 1567 const Class& bigint_class = Class::ZoneHandle( | 1578 const Class& bigint_class = Class::ZoneHandle( |
| 1568 Isolate::Current()->object_store()->bigint_class()); | 1579 Isolate::Current()->object_store()->bigint_class()); |
| 1569 TestClassAndJump(bigint_class, &done); | 1580 TestClassAndJump(bigint_class, &done); |
| 1570 } | 1581 } |
| (...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2704 const Error& error = Error::Handle( | 2715 const Error& error = Error::Handle( |
| 2705 Parser::FormatError(script, token_index, "Error", format, args)); | 2716 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2706 va_end(args); | 2717 va_end(args); |
| 2707 Isolate::Current()->long_jump_base()->Jump(1, error); | 2718 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2708 UNREACHABLE(); | 2719 UNREACHABLE(); |
| 2709 } | 2720 } |
| 2710 | 2721 |
| 2711 } // namespace dart | 2722 } // namespace dart |
| 2712 | 2723 |
| 2713 #endif // defined TARGET_ARCH_X64 | 2724 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |