| 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_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 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1262 intptr_t token_index, | 1262 intptr_t token_index, |
| 1263 const AbstractType& type, | 1263 const AbstractType& type, |
| 1264 bool negate_result) { | 1264 bool negate_result) { |
| 1265 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 1265 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1266 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1266 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1267 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1267 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1268 | 1268 |
| 1269 // All instances are of a subtype of the Object type. | 1269 // All instances are of a subtype of the Object type. |
| 1270 const Type& object_type = | 1270 const Type& object_type = |
| 1271 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1271 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1272 if (type.IsInstantiated() && object_type.IsSubtypeOf(type)) { | 1272 Error& malformed_error = Error::Handle(); |
| 1273 if (type.IsInstantiated() && |
| 1274 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1273 __ PushObject(negate_result ? bool_false : bool_true); | 1275 __ PushObject(negate_result ? bool_false : bool_true); |
| 1274 return; | 1276 return; |
| 1275 } | 1277 } |
| 1276 | 1278 |
| 1277 const Immediate raw_null = | 1279 const Immediate raw_null = |
| 1278 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1280 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1279 Label done; | 1281 Label done; |
| 1280 // If type is instantiated and non-parameterized, we can inline code | 1282 // If type is instantiated and non-parameterized, we can inline code |
| 1281 // checking whether the tested instance is a Smi. | 1283 // checking whether the tested instance is a Smi. |
| 1282 if (type.IsInstantiated()) { | 1284 if (type.IsInstantiated()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1331 } | 1333 } |
| 1332 __ Bind(&runtime_call); | 1334 __ Bind(&runtime_call); |
| 1333 // Fall through to runtime call. | 1335 // Fall through to runtime call. |
| 1334 } else { | 1336 } else { |
| 1335 Label compare_classes; | 1337 Label compare_classes; |
| 1336 __ testl(EAX, Immediate(kSmiTagMask)); | 1338 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1337 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1339 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1338 // Object is Smi. | 1340 // Object is Smi. |
| 1339 const Class& smi_class = Class::Handle(Smi::Class()); | 1341 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1340 // TODO(regis): We should introduce a SmiType. | 1342 // TODO(regis): We should introduce a SmiType. |
| 1343 Error& malformed_error = Error::Handle(); |
| 1341 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1344 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1342 type_class, | 1345 type_class, |
| 1343 TypeArguments::Handle())) { | 1346 TypeArguments::Handle(), |
| 1347 &malformed_error)) { |
| 1344 __ PushObject(negate_result ? bool_false : bool_true); | 1348 __ PushObject(negate_result ? bool_false : bool_true); |
| 1345 } else { | 1349 } else { |
| 1346 __ PushObject(negate_result ? bool_true : bool_false); | 1350 __ PushObject(negate_result ? bool_true : bool_false); |
| 1347 } | 1351 } |
| 1348 __ jmp(&done, Assembler::kNearJump); | 1352 __ jmp(&done, Assembler::kNearJump); |
| 1349 | 1353 |
| 1350 // Compare if the classes are equal. | 1354 // Compare if the classes are equal. |
| 1351 __ Bind(&compare_classes); | 1355 __ Bind(&compare_classes); |
| 1352 const Class* compare_class = NULL; | 1356 const Class* compare_class = NULL; |
| 1353 if (type.IsStringInterface()) { | 1357 if (type.IsStringInterface()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1364 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1368 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1365 __ CompareObject(ECX, *compare_class); | 1369 __ CompareObject(ECX, *compare_class); |
| 1366 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1370 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1367 __ PushObject(negate_result ? bool_false : bool_true); | 1371 __ PushObject(negate_result ? bool_false : bool_true); |
| 1368 __ jmp(&done, Assembler::kNearJump); | 1372 __ jmp(&done, Assembler::kNearJump); |
| 1369 __ Bind(&runtime_call); | 1373 __ Bind(&runtime_call); |
| 1370 } | 1374 } |
| 1371 } | 1375 } |
| 1372 } | 1376 } |
| 1373 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1377 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1378 const Immediate location = |
| 1379 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1380 __ pushl(location); // Push the source location. |
| 1374 __ pushl(EAX); // Push the instance. | 1381 __ pushl(EAX); // Push the instance. |
| 1375 __ PushObject(type); // Push the type. | 1382 __ PushObject(type); // Push the type. |
| 1376 if (!type.IsInstantiated()) { | 1383 if (!type.IsInstantiated()) { |
| 1377 GenerateInstantiatorTypeArguments(token_index); | 1384 GenerateInstantiatorTypeArguments(token_index); |
| 1378 } else { | 1385 } else { |
| 1379 __ pushl(raw_null); // Null instantiator. | 1386 __ pushl(raw_null); // Null instantiator. |
| 1380 } | 1387 } |
| 1381 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1388 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1382 // Pop the two parameters supplied to the runtime entry. The result of the | 1389 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1383 // instanceof runtime call will be left as the result of the operation. | 1390 // instanceof runtime call will be left as the result of the operation. |
| 1384 __ addl(ESP, Immediate(3 * kWordSize)); | 1391 __ addl(ESP, Immediate(4 * kWordSize)); |
| 1385 if (negate_result) { | 1392 if (negate_result) { |
| 1386 Label negate_done; | 1393 Label negate_done; |
| 1387 __ popl(EDX); | 1394 __ popl(EDX); |
| 1388 __ LoadObject(EAX, bool_true); | 1395 __ LoadObject(EAX, bool_true); |
| 1389 __ cmpl(EDX, EAX); | 1396 __ cmpl(EDX, EAX); |
| 1390 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1397 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 1391 __ LoadObject(EAX, bool_false); | 1398 __ LoadObject(EAX, bool_false); |
| 1392 __ Bind(&negate_done); | 1399 __ Bind(&negate_done); |
| 1393 __ pushl(EAX); | 1400 __ pushl(EAX); |
| 1394 } | 1401 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1416 // - object in EAX for successful assignable check (or throws TypeError). | 1423 // - object in EAX for successful assignable check (or throws TypeError). |
| 1417 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1424 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1418 intptr_t token_index, | 1425 intptr_t token_index, |
| 1419 const AbstractType& dst_type, | 1426 const AbstractType& dst_type, |
| 1420 const String& dst_name) { | 1427 const String& dst_name) { |
| 1421 ASSERT(FLAG_enable_type_checks); | 1428 ASSERT(FLAG_enable_type_checks); |
| 1422 ASSERT(token_index >= 0); | 1429 ASSERT(token_index >= 0); |
| 1423 ASSERT(!dst_type.IsNull()); | 1430 ASSERT(!dst_type.IsNull()); |
| 1424 ASSERT(dst_type.IsFinalized()); | 1431 ASSERT(dst_type.IsFinalized()); |
| 1425 | 1432 |
| 1426 // Generate throw new TypeError() if the type is malformed. | |
| 1427 if (dst_type.IsMalformed()) { | |
| 1428 const Error& error = Error::Handle(dst_type.malformed_error()); | |
| 1429 const String& error_message = String::ZoneHandle( | |
| 1430 String::NewSymbol(error.ToErrorCString())); | |
| 1431 __ PushObject(Object::ZoneHandle()); // Make room for the result. | |
| 1432 const Immediate location = | |
| 1433 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | |
| 1434 __ pushl(location); // Push the source location. | |
| 1435 __ pushl(EAX); // Push the source object. | |
| 1436 __ PushObject(error_message); | |
| 1437 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | |
| 1438 // We should never return here. | |
| 1439 __ int3(); | |
| 1440 return; | |
| 1441 } | |
| 1442 | |
| 1443 // Any expression is assignable to the Dynamic type and to the Object type. | 1433 // Any expression is assignable to the Dynamic type and to the Object type. |
| 1444 // Skip the test. | 1434 // Skip the test. |
| 1445 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { | 1435 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 1446 return; | 1436 return; |
| 1447 } | 1437 } |
| 1448 | 1438 |
| 1449 // It is a compile-time error to explicitly return a value (including null) | 1439 // It is a compile-time error to explicitly return a value (including null) |
| 1450 // from a void function. However, functions that do not explicitly return a | 1440 // from a void function. However, functions that do not explicitly return a |
| 1451 // value, implicitly return null. This includes void functions. Therefore, we | 1441 // value, implicitly return null. This includes void functions. Therefore, we |
| 1452 // skip the type test here and trust the parser to only return null in void | 1442 // skip the type test here and trust the parser to only return null in void |
| 1453 // function. | 1443 // function. |
| 1454 if (dst_type.IsVoidType()) { | 1444 if (dst_type.IsVoidType()) { |
| 1455 return; | 1445 return; |
| 1456 } | 1446 } |
| 1457 | 1447 |
| 1458 // A NULL object is always assignable and is returned as result. | 1448 // A null object is always assignable and is returned as result. |
| 1459 const Immediate raw_null = | 1449 const Immediate raw_null = |
| 1460 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1450 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1461 Label done, runtime_call; | 1451 Label done, runtime_call; |
| 1462 __ cmpl(EAX, raw_null); | 1452 __ cmpl(EAX, raw_null); |
| 1463 __ j(EQUAL, &done, Assembler::kNearJump); | 1453 __ j(EQUAL, &done, Assembler::kNearJump); |
| 1464 | 1454 |
| 1455 // Generate throw new TypeError() if the type is malformed. |
| 1456 if (dst_type.IsMalformed()) { |
| 1457 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 1458 const String& error_message = String::ZoneHandle( |
| 1459 String::NewSymbol(error.ToErrorCString())); |
| 1460 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1461 const Immediate location = |
| 1462 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1463 __ pushl(location); // Push the source location. |
| 1464 __ pushl(EAX); // Push the source object. |
| 1465 __ PushObject(dst_name); // Push the name of the destination. |
| 1466 __ PushObject(error_message); |
| 1467 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1468 // We should never return here. |
| 1469 __ int3(); |
| 1470 return; |
| 1471 } |
| 1472 |
| 1465 // If dst_type is instantiated and non-parameterized, we can inline code | 1473 // If dst_type is instantiated and non-parameterized, we can inline code |
| 1466 // checking whether the assigned instance is a Smi. | 1474 // checking whether the assigned instance is a Smi. |
| 1467 if (dst_type.IsInstantiated()) { | 1475 if (dst_type.IsInstantiated()) { |
| 1468 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); | 1476 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); |
| 1469 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); | 1477 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); |
| 1470 // A Smi object cannot be the instance of a parameterized class. | 1478 // A Smi object cannot be the instance of a parameterized class. |
| 1471 // A class equality check is only applicable with a dst type of a | 1479 // A class equality check is only applicable with a dst type of a |
| 1472 // non-parameterized class or with a raw dst type of a parameterized class. | 1480 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1473 if (dst_class_has_type_arguments) { | 1481 if (dst_class_has_type_arguments) { |
| 1474 const AbstractTypeArguments& dst_type_arguments = | 1482 const AbstractTypeArguments& dst_type_arguments = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1492 } | 1500 } |
| 1493 // Fall through to runtime class. | 1501 // Fall through to runtime class. |
| 1494 } | 1502 } |
| 1495 } else { // dst_type has NO type arguments. | 1503 } else { // dst_type has NO type arguments. |
| 1496 Label compare_classes; | 1504 Label compare_classes; |
| 1497 __ testl(EAX, Immediate(kSmiTagMask)); | 1505 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1498 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1506 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1499 // Object is Smi. | 1507 // Object is Smi. |
| 1500 const Class& smi_class = Class::Handle(Smi::Class()); | 1508 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1501 // TODO(regis): We should introduce a SmiType. | 1509 // TODO(regis): We should introduce a SmiType. |
| 1510 Error& malformed_error = Error::Handle(); |
| 1502 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1511 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1503 dst_type_class, | 1512 dst_type_class, |
| 1504 TypeArguments::Handle())) { | 1513 TypeArguments::Handle(), |
| 1514 &malformed_error)) { |
| 1505 // Successful assignable type check: return object in EAX. | 1515 // Successful assignable type check: return object in EAX. |
| 1506 __ jmp(&done, Assembler::kNearJump); | 1516 __ jmp(&done, Assembler::kNearJump); |
| 1507 } else { | 1517 } else { |
| 1508 // Failed assignable type check: call runtime to throw TypeError. | 1518 // Failed assignable type check: call runtime to throw TypeError. |
| 1509 __ jmp(&runtime_call, Assembler::kNearJump); | 1519 __ jmp(&runtime_call, Assembler::kNearJump); |
| 1510 } | 1520 } |
| 1511 // Compare if the classes are equal. | 1521 // Compare if the classes are equal. |
| 1512 __ Bind(&compare_classes); | 1522 __ Bind(&compare_classes); |
| 1513 // If dst_type is an interface, we can skip the class equality check, | 1523 // If dst_type is an interface, we can skip the class equality check, |
| 1514 // because instances cannot be of an interface type. | 1524 // because instances cannot be of an interface type. |
| 1515 if (!dst_type_class.is_interface()) { | 1525 if (!dst_type_class.is_interface()) { |
| 1516 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1526 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1517 TestClassAndJump(dst_type_class, &done); | 1527 TestClassAndJump(dst_type_class, &done); |
| 1518 } else { | 1528 } else { |
| 1519 // However, for specific core library interfaces, we can check for | 1529 // However, for specific core library interfaces, we can check for |
| 1520 // specific core library classes. | 1530 // specific core library classes. |
| 1531 Error& malformed_error = Error::Handle(); |
| 1521 if (dst_type.IsBoolInterface()) { | 1532 if (dst_type.IsBoolInterface()) { |
| 1522 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1533 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1523 const Class& bool_class = Class::ZoneHandle( | 1534 const Class& bool_class = Class::ZoneHandle( |
| 1524 Isolate::Current()->object_store()->bool_class()); | 1535 Isolate::Current()->object_store()->bool_class()); |
| 1525 TestClassAndJump(bool_class, &done); | 1536 TestClassAndJump(bool_class, &done); |
| 1526 } else if (dst_type.IsSubtypeOf( | 1537 } else if (dst_type.IsSubtypeOf( |
| 1527 Type::Handle(Type::NumberInterface()))) { | 1538 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1528 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1539 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1529 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { | 1540 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { |
| 1530 // We already checked for Smi above. | 1541 // We already checked for Smi above. |
| 1531 const Class& mint_class = Class::ZoneHandle( | 1542 const Class& mint_class = Class::ZoneHandle( |
| 1532 Isolate::Current()->object_store()->mint_class()); | 1543 Isolate::Current()->object_store()->mint_class()); |
| 1533 TestClassAndJump(mint_class, &done); | 1544 TestClassAndJump(mint_class, &done); |
| 1534 const Class& bigint_class = Class::ZoneHandle( | 1545 const Class& bigint_class = Class::ZoneHandle( |
| 1535 Isolate::Current()->object_store()->bigint_class()); | 1546 Isolate::Current()->object_store()->bigint_class()); |
| 1536 TestClassAndJump(bigint_class, &done); | 1547 TestClassAndJump(bigint_class, &done); |
| 1537 } | 1548 } |
| (...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2671 const Error& error = Error::Handle( | 2682 const Error& error = Error::Handle( |
| 2672 Parser::FormatError(script, token_index, "Error", format, args)); | 2683 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2673 va_end(args); | 2684 va_end(args); |
| 2674 Isolate::Current()->long_jump_base()->Jump(1, error); | 2685 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2675 UNREACHABLE(); | 2686 UNREACHABLE(); |
| 2676 } | 2687 } |
| 2677 | 2688 |
| 2678 } // namespace dart | 2689 } // namespace dart |
| 2679 | 2690 |
| 2680 #endif // defined TARGET_ARCH_IA32 | 2691 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |