| 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 1296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1307 intptr_t token_index, | 1307 intptr_t token_index, |
| 1308 const AbstractType& type, | 1308 const AbstractType& type, |
| 1309 bool negate_result) { | 1309 bool negate_result) { |
| 1310 ASSERT(type.IsFinalized() && !type.IsMalformed()); | 1310 ASSERT(type.IsFinalized() && !type.IsMalformed()); |
| 1311 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 1311 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 1312 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 1312 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| 1313 | 1313 |
| 1314 // All instances are of a subtype of the Object type. | 1314 // All instances are of a subtype of the Object type. |
| 1315 const Type& object_type = | 1315 const Type& object_type = |
| 1316 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1316 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1317 if (type.IsInstantiated() && object_type.IsSubtypeOf(type)) { | 1317 Error& malformed_error = Error::Handle(); |
| 1318 if (type.IsInstantiated() && |
| 1319 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1318 __ PushObject(negate_result ? bool_false : bool_true); | 1320 __ PushObject(negate_result ? bool_false : bool_true); |
| 1319 return; | 1321 return; |
| 1320 } | 1322 } |
| 1321 | 1323 |
| 1322 const Immediate raw_null = | 1324 const Immediate raw_null = |
| 1323 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1325 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1324 Label done; | 1326 Label done; |
| 1325 // If type is instantiated and non-parameterized, we can inline code | 1327 // If type is instantiated and non-parameterized, we can inline code |
| 1326 // checking whether the tested instance is a Smi. | 1328 // checking whether the tested instance is a Smi. |
| 1327 if (type.IsInstantiated()) { | 1329 if (type.IsInstantiated()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1376 } | 1378 } |
| 1377 __ Bind(&runtime_call); | 1379 __ Bind(&runtime_call); |
| 1378 // Fall through to runtime call. | 1380 // Fall through to runtime call. |
| 1379 } else { | 1381 } else { |
| 1380 Label compare_classes; | 1382 Label compare_classes; |
| 1381 __ testl(EAX, Immediate(kSmiTagMask)); | 1383 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1382 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1384 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1383 // Object is Smi. | 1385 // Object is Smi. |
| 1384 const Class& smi_class = Class::Handle(Smi::Class()); | 1386 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1385 // TODO(regis): We should introduce a SmiType. | 1387 // TODO(regis): We should introduce a SmiType. |
| 1388 Error& malformed_error = Error::Handle(); |
| 1386 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1389 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1387 type_class, | 1390 type_class, |
| 1388 TypeArguments::Handle())) { | 1391 TypeArguments::Handle(), |
| 1392 &malformed_error)) { |
| 1389 __ PushObject(negate_result ? bool_false : bool_true); | 1393 __ PushObject(negate_result ? bool_false : bool_true); |
| 1390 } else { | 1394 } else { |
| 1391 __ PushObject(negate_result ? bool_true : bool_false); | 1395 __ PushObject(negate_result ? bool_true : bool_false); |
| 1392 } | 1396 } |
| 1393 __ jmp(&done, Assembler::kNearJump); | 1397 __ jmp(&done, Assembler::kNearJump); |
| 1394 | 1398 |
| 1395 // Compare if the classes are equal. | 1399 // Compare if the classes are equal. |
| 1396 __ Bind(&compare_classes); | 1400 __ Bind(&compare_classes); |
| 1397 const Class* compare_class = NULL; | 1401 const Class* compare_class = NULL; |
| 1398 if (type.IsStringInterface()) { | 1402 if (type.IsStringInterface()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1409 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1413 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1410 __ CompareObject(ECX, *compare_class); | 1414 __ CompareObject(ECX, *compare_class); |
| 1411 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1415 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1412 __ PushObject(negate_result ? bool_false : bool_true); | 1416 __ PushObject(negate_result ? bool_false : bool_true); |
| 1413 __ jmp(&done, Assembler::kNearJump); | 1417 __ jmp(&done, Assembler::kNearJump); |
| 1414 __ Bind(&runtime_call); | 1418 __ Bind(&runtime_call); |
| 1415 } | 1419 } |
| 1416 } | 1420 } |
| 1417 } | 1421 } |
| 1418 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1422 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1423 const Immediate location = |
| 1424 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1425 __ pushl(location); // Push the source location. |
| 1419 __ pushl(EAX); // Push the instance. | 1426 __ pushl(EAX); // Push the instance. |
| 1420 __ PushObject(type); // Push the type. | 1427 __ PushObject(type); // Push the type. |
| 1421 if (!type.IsInstantiated()) { | 1428 if (!type.IsInstantiated()) { |
| 1422 GenerateInstantiatorTypeArguments(token_index); | 1429 GenerateInstantiatorTypeArguments(token_index); |
| 1423 } else { | 1430 } else { |
| 1424 __ pushl(raw_null); // Null instantiator. | 1431 __ pushl(raw_null); // Null instantiator. |
| 1425 } | 1432 } |
| 1426 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1433 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1427 // Pop the two parameters supplied to the runtime entry. The result of the | 1434 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1428 // instanceof runtime call will be left as the result of the operation. | 1435 // instanceof runtime call will be left as the result of the operation. |
| 1429 __ addl(ESP, Immediate(3 * kWordSize)); | 1436 __ addl(ESP, Immediate(4 * kWordSize)); |
| 1430 if (negate_result) { | 1437 if (negate_result) { |
| 1431 Label negate_done; | 1438 Label negate_done; |
| 1432 __ popl(EDX); | 1439 __ popl(EDX); |
| 1433 __ LoadObject(EAX, bool_true); | 1440 __ LoadObject(EAX, bool_true); |
| 1434 __ cmpl(EDX, EAX); | 1441 __ cmpl(EDX, EAX); |
| 1435 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1442 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 1436 __ LoadObject(EAX, bool_false); | 1443 __ LoadObject(EAX, bool_false); |
| 1437 __ Bind(&negate_done); | 1444 __ Bind(&negate_done); |
| 1438 __ pushl(EAX); | 1445 __ pushl(EAX); |
| 1439 } | 1446 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1461 // - object in EAX for successful assignable check (or throws TypeError). | 1468 // - object in EAX for successful assignable check (or throws TypeError). |
| 1462 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, | 1469 void CodeGenerator::GenerateAssertAssignable(intptr_t node_id, |
| 1463 intptr_t token_index, | 1470 intptr_t token_index, |
| 1464 const AbstractType& dst_type, | 1471 const AbstractType& dst_type, |
| 1465 const String& dst_name) { | 1472 const String& dst_name) { |
| 1466 ASSERT(FLAG_enable_type_checks); | 1473 ASSERT(FLAG_enable_type_checks); |
| 1467 ASSERT(token_index >= 0); | 1474 ASSERT(token_index >= 0); |
| 1468 ASSERT(!dst_type.IsNull()); | 1475 ASSERT(!dst_type.IsNull()); |
| 1469 ASSERT(dst_type.IsFinalized()); | 1476 ASSERT(dst_type.IsFinalized()); |
| 1470 | 1477 |
| 1471 // Generate throw new TypeError() if the type is malformed. | |
| 1472 if (dst_type.IsMalformed()) { | |
| 1473 const Error& error = Error::Handle(dst_type.malformed_error()); | |
| 1474 const String& error_message = String::ZoneHandle( | |
| 1475 String::NewSymbol(error.ToErrorCString())); | |
| 1476 __ PushObject(Object::ZoneHandle()); // Make room for the result. | |
| 1477 const Immediate location = | |
| 1478 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | |
| 1479 __ pushl(location); // Push the source location. | |
| 1480 __ pushl(EAX); // Push the source object. | |
| 1481 __ PushObject(error_message); | |
| 1482 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | |
| 1483 // We should never return here. | |
| 1484 __ int3(); | |
| 1485 return; | |
| 1486 } | |
| 1487 | |
| 1488 // Any expression is assignable to the Dynamic type and to the Object type. | 1478 // Any expression is assignable to the Dynamic type and to the Object type. |
| 1489 // Skip the test. | 1479 // Skip the test. |
| 1490 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { | 1480 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 1491 return; | 1481 return; |
| 1492 } | 1482 } |
| 1493 | 1483 |
| 1494 // It is a compile-time error to explicitly return a value (including null) | 1484 // It is a compile-time error to explicitly return a value (including null) |
| 1495 // from a void function. However, functions that do not explicitly return a | 1485 // from a void function. However, functions that do not explicitly return a |
| 1496 // value, implicitly return null. This includes void functions. Therefore, we | 1486 // value, implicitly return null. This includes void functions. Therefore, we |
| 1497 // skip the type test here and trust the parser to only return null in void | 1487 // skip the type test here and trust the parser to only return null in void |
| 1498 // function. | 1488 // function. |
| 1499 if (dst_type.IsVoidType()) { | 1489 if (dst_type.IsVoidType()) { |
| 1500 return; | 1490 return; |
| 1501 } | 1491 } |
| 1502 | 1492 |
| 1503 // A NULL object is always assignable and is returned as result. | 1493 // A null object is always assignable and is returned as result. |
| 1504 const Immediate raw_null = | 1494 const Immediate raw_null = |
| 1505 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1495 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1506 Label done, runtime_call; | 1496 Label done, runtime_call; |
| 1507 __ cmpl(EAX, raw_null); | 1497 __ cmpl(EAX, raw_null); |
| 1508 __ j(EQUAL, &done, Assembler::kNearJump); | 1498 __ j(EQUAL, &done, Assembler::kNearJump); |
| 1509 | 1499 |
| 1500 // Generate throw new TypeError() if the type is malformed. |
| 1501 if (dst_type.IsMalformed()) { |
| 1502 const Error& error = Error::Handle(dst_type.malformed_error()); |
| 1503 const String& error_message = String::ZoneHandle( |
| 1504 String::NewSymbol(error.ToErrorCString())); |
| 1505 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1506 const Immediate location = |
| 1507 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1508 __ pushl(location); // Push the source location. |
| 1509 __ pushl(EAX); // Push the source object. |
| 1510 __ PushObject(dst_name); // Push the name of the destination. |
| 1511 __ PushObject(error_message); |
| 1512 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1513 // We should never return here. |
| 1514 __ int3(); |
| 1515 return; |
| 1516 } |
| 1517 |
| 1510 // If dst_type is instantiated and non-parameterized, we can inline code | 1518 // If dst_type is instantiated and non-parameterized, we can inline code |
| 1511 // checking whether the assigned instance is a Smi. | 1519 // checking whether the assigned instance is a Smi. |
| 1512 if (dst_type.IsInstantiated()) { | 1520 if (dst_type.IsInstantiated()) { |
| 1513 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); | 1521 const Class& dst_type_class = Class::ZoneHandle(dst_type.type_class()); |
| 1514 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); | 1522 const bool dst_class_has_type_arguments = dst_type_class.HasTypeArguments(); |
| 1515 // A Smi object cannot be the instance of a parameterized class. | 1523 // A Smi object cannot be the instance of a parameterized class. |
| 1516 // A class equality check is only applicable with a dst type of a | 1524 // A class equality check is only applicable with a dst type of a |
| 1517 // non-parameterized class or with a raw dst type of a parameterized class. | 1525 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1518 if (dst_class_has_type_arguments) { | 1526 if (dst_class_has_type_arguments) { |
| 1519 const AbstractTypeArguments& dst_type_arguments = | 1527 const AbstractTypeArguments& dst_type_arguments = |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1537 } | 1545 } |
| 1538 // Fall through to runtime class. | 1546 // Fall through to runtime class. |
| 1539 } | 1547 } |
| 1540 } else { // dst_type has NO type arguments. | 1548 } else { // dst_type has NO type arguments. |
| 1541 Label compare_classes; | 1549 Label compare_classes; |
| 1542 __ testl(EAX, Immediate(kSmiTagMask)); | 1550 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1543 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1551 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1544 // Object is Smi. | 1552 // Object is Smi. |
| 1545 const Class& smi_class = Class::Handle(Smi::Class()); | 1553 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1546 // TODO(regis): We should introduce a SmiType. | 1554 // TODO(regis): We should introduce a SmiType. |
| 1555 Error& malformed_error = Error::Handle(); |
| 1547 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1556 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1548 dst_type_class, | 1557 dst_type_class, |
| 1549 TypeArguments::Handle())) { | 1558 TypeArguments::Handle(), |
| 1559 &malformed_error)) { |
| 1550 // Successful assignable type check: return object in EAX. | 1560 // Successful assignable type check: return object in EAX. |
| 1551 __ jmp(&done, Assembler::kNearJump); | 1561 __ jmp(&done, Assembler::kNearJump); |
| 1552 } else { | 1562 } else { |
| 1553 // Failed assignable type check: call runtime to throw TypeError. | 1563 // Failed assignable type check: call runtime to throw TypeError. |
| 1554 __ jmp(&runtime_call, Assembler::kNearJump); | 1564 __ jmp(&runtime_call, Assembler::kNearJump); |
| 1555 } | 1565 } |
| 1556 // Compare if the classes are equal. | 1566 // Compare if the classes are equal. |
| 1557 __ Bind(&compare_classes); | 1567 __ Bind(&compare_classes); |
| 1558 // If dst_type is an interface, we can skip the class equality check, | 1568 // If dst_type is an interface, we can skip the class equality check, |
| 1559 // because instances cannot be of an interface type. | 1569 // because instances cannot be of an interface type. |
| 1560 if (!dst_type_class.is_interface()) { | 1570 if (!dst_type_class.is_interface()) { |
| 1561 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1571 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1562 TestClassAndJump(dst_type_class, &done); | 1572 TestClassAndJump(dst_type_class, &done); |
| 1563 } else { | 1573 } else { |
| 1564 // However, for specific core library interfaces, we can check for | 1574 // However, for specific core library interfaces, we can check for |
| 1565 // specific core library classes. | 1575 // specific core library classes. |
| 1576 Error& malformed_error = Error::Handle(); |
| 1566 if (dst_type.IsBoolInterface()) { | 1577 if (dst_type.IsBoolInterface()) { |
| 1567 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1578 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1568 const Class& bool_class = Class::ZoneHandle( | 1579 const Class& bool_class = Class::ZoneHandle( |
| 1569 Isolate::Current()->object_store()->bool_class()); | 1580 Isolate::Current()->object_store()->bool_class()); |
| 1570 TestClassAndJump(bool_class, &done); | 1581 TestClassAndJump(bool_class, &done); |
| 1571 } else if (dst_type.IsSubtypeOf( | 1582 } else if (dst_type.IsSubtypeOf( |
| 1572 Type::Handle(Type::NumberInterface()))) { | 1583 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1573 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1584 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1574 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { | 1585 if (dst_type.IsIntInterface() || dst_type.IsNumberInterface()) { |
| 1575 // We already checked for Smi above. | 1586 // We already checked for Smi above. |
| 1576 const Class& mint_class = Class::ZoneHandle( | 1587 const Class& mint_class = Class::ZoneHandle( |
| 1577 Isolate::Current()->object_store()->mint_class()); | 1588 Isolate::Current()->object_store()->mint_class()); |
| 1578 TestClassAndJump(mint_class, &done); | 1589 TestClassAndJump(mint_class, &done); |
| 1579 const Class& bigint_class = Class::ZoneHandle( | 1590 const Class& bigint_class = Class::ZoneHandle( |
| 1580 Isolate::Current()->object_store()->bigint_class()); | 1591 Isolate::Current()->object_store()->bigint_class()); |
| 1581 TestClassAndJump(bigint_class, &done); | 1592 TestClassAndJump(bigint_class, &done); |
| 1582 } | 1593 } |
| (...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2716 const Error& error = Error::Handle( | 2727 const Error& error = Error::Handle( |
| 2717 Parser::FormatError(script, token_index, "Error", format, args)); | 2728 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2718 va_end(args); | 2729 va_end(args); |
| 2719 Isolate::Current()->long_jump_base()->Jump(1, error); | 2730 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2720 UNREACHABLE(); | 2731 UNREACHABLE(); |
| 2721 } | 2732 } |
| 2722 | 2733 |
| 2723 } // namespace dart | 2734 } // namespace dart |
| 2724 | 2735 |
| 2725 #endif // defined TARGET_ARCH_IA32 | 2736 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |