| 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 1239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 intptr_t token_index, | 1250 intptr_t token_index, |
| 1251 const AbstractType& type, | 1251 const AbstractType& type, |
| 1252 bool negate_result) { | 1252 bool negate_result) { |
| 1253 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 1253 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1254 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1254 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1255 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1255 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1256 | 1256 |
| 1257 // All instances are of a subtype of the Object type. | 1257 // All instances are of a subtype of the Object type. |
| 1258 const Type& object_type = | 1258 const Type& object_type = |
| 1259 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1259 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1260 if (type.IsInstantiated() && object_type.IsSubtypeOf(type)) { | 1260 Error& malformed_error = Error::Handle(); |
| 1261 if (type.IsInstantiated() && |
| 1262 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1261 __ PushObject(negate_result ? bool_false : bool_true); | 1263 __ PushObject(negate_result ? bool_false : bool_true); |
| 1262 return; | 1264 return; |
| 1263 } | 1265 } |
| 1264 | 1266 |
| 1265 const Immediate raw_null = | 1267 const Immediate raw_null = |
| 1266 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1268 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1267 Label done; | 1269 Label done; |
| 1268 // If type is instantiated and non-parameterized, we can inline code | 1270 // If type is instantiated and non-parameterized, we can inline code |
| 1269 // checking whether the tested instance is a Smi. | 1271 // checking whether the tested instance is a Smi. |
| 1270 if (type.IsInstantiated()) { | 1272 if (type.IsInstantiated()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1319 } | 1321 } |
| 1320 __ Bind(&runtime_call); | 1322 __ Bind(&runtime_call); |
| 1321 // Fall through to runtime call. | 1323 // Fall through to runtime call. |
| 1322 } else { | 1324 } else { |
| 1323 Label compare_classes; | 1325 Label compare_classes; |
| 1324 __ testq(RAX, Immediate(kSmiTagMask)); | 1326 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1325 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1327 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1326 // Object is Smi. | 1328 // Object is Smi. |
| 1327 const Class& smi_class = Class::Handle(Smi::Class()); | 1329 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1328 // TODO(regis): We should introduce a SmiType. | 1330 // TODO(regis): We should introduce a SmiType. |
| 1331 Error& malformed_error = Error::Handle(); |
| 1329 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1332 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1330 type_class, | 1333 type_class, |
| 1331 TypeArguments::Handle())) { | 1334 TypeArguments::Handle(), |
| 1335 &malformed_error)) { |
| 1332 __ PushObject(negate_result ? bool_false : bool_true); | 1336 __ PushObject(negate_result ? bool_false : bool_true); |
| 1333 } else { | 1337 } else { |
| 1334 __ PushObject(negate_result ? bool_true : bool_false); | 1338 __ PushObject(negate_result ? bool_true : bool_false); |
| 1335 } | 1339 } |
| 1336 __ jmp(&done); | 1340 __ jmp(&done); |
| 1337 | 1341 |
| 1338 // Compare if the classes are equal. | 1342 // Compare if the classes are equal. |
| 1339 __ Bind(&compare_classes); | 1343 __ Bind(&compare_classes); |
| 1340 const Class* compare_class = NULL; | 1344 const Class* compare_class = NULL; |
| 1341 if (type.IsStringInterface()) { | 1345 if (type.IsStringInterface()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1352 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1356 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1353 __ CompareObject(RCX, *compare_class); | 1357 __ CompareObject(RCX, *compare_class); |
| 1354 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1358 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1355 __ PushObject(negate_result ? bool_false : bool_true); | 1359 __ PushObject(negate_result ? bool_false : bool_true); |
| 1356 __ jmp(&done, Assembler::kNearJump); | 1360 __ jmp(&done, Assembler::kNearJump); |
| 1357 __ Bind(&runtime_call); | 1361 __ Bind(&runtime_call); |
| 1358 } | 1362 } |
| 1359 } | 1363 } |
| 1360 } | 1364 } |
| 1361 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1365 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1366 const Immediate location = |
| 1367 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); |
| 1368 __ pushq(location); // Push the source location. |
| 1362 __ pushq(RAX); // Push the instance. | 1369 __ pushq(RAX); // Push the instance. |
| 1363 __ PushObject(type); // Push the type. | 1370 __ PushObject(type); // Push the type. |
| 1364 if (!type.IsInstantiated()) { | 1371 if (!type.IsInstantiated()) { |
| 1365 GenerateInstantiatorTypeArguments(token_index); | 1372 GenerateInstantiatorTypeArguments(token_index); |
| 1366 } else { | 1373 } else { |
| 1367 __ pushq(raw_null); // Null instantiator. | 1374 __ pushq(raw_null); // Null instantiator. |
| 1368 } | 1375 } |
| 1369 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1376 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1370 // Pop the two parameters supplied to the runtime entry. The result of the | 1377 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1371 // instanceof runtime call will be left as the result of the operation. | 1378 // instanceof runtime call will be left as the result of the operation. |
| 1372 __ addq(RSP, Immediate(3 * kWordSize)); | 1379 __ addq(RSP, Immediate(4 * kWordSize)); |
| 1373 if (negate_result) { | 1380 if (negate_result) { |
| 1374 Label negate_done; | 1381 Label negate_done; |
| 1375 __ popq(RDX); | 1382 __ popq(RDX); |
| 1376 __ LoadObject(RAX, bool_true); | 1383 __ LoadObject(RAX, bool_true); |
| 1377 __ cmpq(RDX, RAX); | 1384 __ cmpq(RDX, RAX); |
| 1378 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1385 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 1379 __ LoadObject(RAX, bool_false); | 1386 __ LoadObject(RAX, bool_false); |
| 1380 __ Bind(&negate_done); | 1387 __ Bind(&negate_done); |
| 1381 __ pushq(RAX); | 1388 __ pushq(RAX); |
| 1382 } | 1389 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1404 // - object in RAX for successful assignable check (or throws TypeError). | 1411 // - object in RAX for successful assignable check (or throws TypeError). |
| 1405 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1412 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1406 intptr_t token_index, | 1413 intptr_t token_index, |
| 1407 const AbstractType& dst_type, | 1414 const AbstractType& dst_type, |
| 1408 const String& dst_name) { | 1415 const String& dst_name) { |
| 1409 ASSERT(FLAG_enable_type_checks); | 1416 ASSERT(FLAG_enable_type_checks); |
| 1410 ASSERT(token_index >= 0); | 1417 ASSERT(token_index >= 0); |
| 1411 ASSERT(!dst_type.IsNull()); | 1418 ASSERT(!dst_type.IsNull()); |
| 1412 ASSERT(dst_type.IsFinalized()); | 1419 ASSERT(dst_type.IsFinalized()); |
| 1413 | 1420 |
| 1414 // Generate throw new TypeError() if the type is malformed. | |
| 1415 if (dst_type.IsMalformed()) { | |
| 1416 const Error& error = Error::Handle(dst_type.malformed_error()); | |
| 1417 const String& error_message = String::ZoneHandle( | |
| 1418 String::NewSymbol(error.ToErrorCString())); | |
| 1419 __ PushObject(Object::ZoneHandle()); // Make room for the result. | |
| 1420 const Immediate location = | |
| 1421 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); | |
| 1422 __ pushq(location); // Push the source location. | |
| 1423 __ pushq(RAX); // Push the source object. | |
| 1424 __ PushObject(error_message); | |
| 1425 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | |
| 1426 // We should never return here. | |
| 1427 __ int3(); | |
| 1428 return; | |
| 1429 } | |
| 1430 | |
| 1431 // Any expression is assignable to the Dynamic type and to the Object type. | 1421 // Any expression is assignable to the Dynamic type and to the Object type. |
| 1432 // Skip the test. | 1422 // Skip the test. |
| 1433 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { | 1423 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 1434 return; | 1424 return; |
| 1435 } | 1425 } |
| 1436 | 1426 |
| 1437 // It is a compile-time error to explicitly return a value (including null) | 1427 // It is a compile-time error to explicitly return a value (including null) |
| 1438 // from a void function. However, functions that do not explicitly return a | 1428 // from a void function. However, functions that do not explicitly return a |
| 1439 // value, implicitly return null. This includes void functions. Therefore, we | 1429 // value, implicitly return null. This includes void functions. Therefore, we |
| 1440 // skip the type test here and trust the parser to only return null in void | 1430 // skip the type test here and trust the parser to only return null in void |
| 1441 // function. | 1431 // function. |
| 1442 if (dst_type.IsVoidType()) { | 1432 if (dst_type.IsVoidType()) { |
| 1443 return; | 1433 return; |
| 1444 } | 1434 } |
| 1445 | 1435 |
| 1446 // A NULL object is always assignable and is returned as result. | 1436 // A null object is always assignable and is returned as result. |
| 1447 const Immediate raw_null = | 1437 const Immediate raw_null = |
| 1448 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1438 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1449 Label done, runtime_call; | 1439 Label done, runtime_call; |
| 1450 __ cmpq(RAX, raw_null); | 1440 __ cmpq(RAX, raw_null); |
| 1451 __ j(EQUAL, &done); | 1441 __ j(EQUAL, &done); |
| 1452 | 1442 |
| 1443 // Generate throw new TypeError() if the type is malformed. |
| 1444 if (dst_type.IsMalformed()) { |
| 1445 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 1446 const String& error_message = String::ZoneHandle( |
| 1447 String::NewSymbol(error.ToErrorCString())); |
| 1448 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1449 const Immediate location = |
| 1450 Immediate(reinterpret_cast<int64_t>(Smi::New(token_index))); |
| 1451 __ pushq(location); // Push the source location. |
| 1452 __ pushq(RAX); // Push the source object. |
| 1453 __ PushObject(dst_name); // Push the name of the destination. |
| 1454 __ PushObject(error_message); |
| 1455 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1456 // We should never return here. |
| 1457 __ int3(); |
| 1458 return; |
| 1459 } |
| 1460 |
| 1453 // If dst_type is instantiated and non-parameterized, we can inline code | 1461 // If dst_type is instantiated and non-parameterized, we can inline code |
| 1454 // checking whether the assigned instance is a Smi. | 1462 // checking whether the assigned instance is a Smi. |
| 1455 if (dst_type.IsInstantiated()) { | 1463 if (dst_type.IsInstantiated()) { |
| 1456 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); | 1464 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); |
| 1457 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); | 1465 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); |
| 1458 // A Smi object cannot be the instance of a parameterized class. | 1466 // A Smi object cannot be the instance of a parameterized class. |
| 1459 // A class equality check is only applicable with a dst type of a | 1467 // A class equality check is only applicable with a dst type of a |
| 1460 // non-parameterized class or with a raw dst type of a parameterized class. | 1468 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1461 if (dst_class_has_type_arguments) { | 1469 if (dst_class_has_type_arguments) { |
| 1462 const AbstractTypeArguments& dst_type_arguments = | 1470 const AbstractTypeArguments& dst_type_arguments = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1480 } | 1488 } |
| 1481 // Fall through to runtime class. | 1489 // Fall through to runtime class. |
| 1482 } | 1490 } |
| 1483 } else { // dst_type has NO type arguments. | 1491 } else { // dst_type has NO type arguments. |
| 1484 Label compare_classes; | 1492 Label compare_classes; |
| 1485 __ testq(RAX, Immediate(kSmiTagMask)); | 1493 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1486 __ j(NOT_ZERO, &compare_classes); | 1494 __ j(NOT_ZERO, &compare_classes); |
| 1487 // Object is Smi. | 1495 // Object is Smi. |
| 1488 const Class& smi_class = Class::Handle(Smi::Class()); | 1496 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1489 // TODO(regis): We should introduce a SmiType. | 1497 // TODO(regis): We should introduce a SmiType. |
| 1498 Error& malformed_error = Error::Handle(); |
| 1490 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1499 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1491 dst_type_class, | 1500 dst_type_class, |
| 1492 TypeArguments::Handle())) { | 1501 TypeArguments::Handle(), |
| 1502 &malformed_error)) { |
| 1493 // Successful assignable type check: return object in RAX. | 1503 // Successful assignable type check: return object in RAX. |
| 1494 __ jmp(&done); | 1504 __ jmp(&done); |
| 1495 } else { | 1505 } else { |
| 1496 // Failed assignable type check: call runtime to throw TypeError. | 1506 // Failed assignable type check: call runtime to throw TypeError. |
| 1497 __ jmp(&runtime_call); | 1507 __ jmp(&runtime_call); |
| 1498 } | 1508 } |
| 1499 // Compare if the classes are equal. | 1509 // Compare if the classes are equal. |
| 1500 __ Bind(&compare_classes); | 1510 __ Bind(&compare_classes); |
| 1501 // If dst_type is an interface, we can skip the class equality check, | 1511 // If dst_type is an interface, we can skip the class equality check, |
| 1502 // because instances cannot be of an interface type. | 1512 // because instances cannot be of an interface type. |
| 1503 if (!dst_type_class.is_interface()) { | 1513 if (!dst_type_class.is_interface()) { |
| 1504 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1514 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1505 TestClassAndJump(dst_type_class, &done); | 1515 TestClassAndJump(dst_type_class, &done); |
| 1506 } else { | 1516 } else { |
| 1507 // However, for specific core library interfaces, we can check for | 1517 // However, for specific core library interfaces, we can check for |
| 1508 // specific core library classes. | 1518 // specific core library classes. |
| 1519 Error& malformed_error = Error::Handle(); |
| 1509 if (dst_type.IsBoolInterface()) { | 1520 if (dst_type.IsBoolInterface()) { |
| 1510 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1521 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1511 const Class& bool_class = Class::ZoneHandle( | 1522 const Class& bool_class = Class::ZoneHandle( |
| 1512 Isolate::Current()->object_store()->bool_class()); | 1523 Isolate::Current()->object_store()->bool_class()); |
| 1513 TestClassAndJump(bool_class, &done); | 1524 TestClassAndJump(bool_class, &done); |
| 1514 } else if (dst_type.IsSubtypeOf( | 1525 } else if (dst_type.IsSubtypeOf( |
| 1515 Type::Handle(Type::NumberInterface()))) { | 1526 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1516 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); | 1527 __ movq(RCX, FieldAddress(RAX, Object::class_offset())); |
| 1517 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { | 1528 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { |
| 1518 // We already checked for Smi above. | 1529 // We already checked for Smi above. |
| 1519 const Class& mint_class = Class::ZoneHandle( | 1530 const Class& mint_class = Class::ZoneHandle( |
| 1520 Isolate::Current()->object_store()->mint_class()); | 1531 Isolate::Current()->object_store()->mint_class()); |
| 1521 TestClassAndJump(mint_class, &done); | 1532 TestClassAndJump(mint_class, &done); |
| 1522 const Class& bigint_class = Class::ZoneHandle( | 1533 const Class& bigint_class = Class::ZoneHandle( |
| 1523 Isolate::Current()->object_store()->bigint_class()); | 1534 Isolate::Current()->object_store()->bigint_class()); |
| 1524 TestClassAndJump(bigint_class, &done); | 1535 TestClassAndJump(bigint_class, &done); |
| 1525 } | 1536 } |
| (...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2659 const Error& error = Error::Handle( | 2670 const Error& error = Error::Handle( |
| 2660 Parser::FormatError(script, token_index, "Error", format, args)); | 2671 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2661 va_end(args); | 2672 va_end(args); |
| 2662 Isolate::Current()->long_jump_base()->Jump(1, error); | 2673 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2663 UNREACHABLE(); | 2674 UNREACHABLE(); |
| 2664 } | 2675 } |
| 2665 | 2676 |
| 2666 } // namespace dart | 2677 } // namespace dart |
| 2667 | 2678 |
| 2668 #endif // defined TARGET_ARCH_X64 | 2679 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |