| 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 1267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 |
| 1288 // If instanceof type test cannot be performed successfully at compile time and | 1347 // If instanceof type test cannot be performed successfully at compile time and |
| 1289 // therefore eliminated, optimize it by adding inlined tests for: | 1348 // therefore eliminated, optimize it by adding inlined tests for: |
| 1290 // - NULL -> return false. | 1349 // - NULL -> return false. |
| 1291 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1350 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1292 // - Class equality (only if class is not parameterized). | 1351 // - Class equality (only if class is not parameterized). |
| 1293 // Inputs: | 1352 // Inputs: |
| 1294 // - EAX: object. | 1353 // - EAX: object. |
| 1295 // Destroys ECX. | 1354 // Destroys ECX. |
| 1296 // Returns: | 1355 // Returns: |
| 1297 // - true or false on stack. | 1356 // - true or false on stack. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1334 &malformed_error)) { | 1393 &malformed_error)) { |
| 1335 __ PushObject(negate_result ? bool_false : bool_true); | 1394 __ PushObject(negate_result ? bool_false : bool_true); |
| 1336 } else { | 1395 } else { |
| 1337 ASSERT(malformed_error.IsNull()); | 1396 ASSERT(malformed_error.IsNull()); |
| 1338 __ PushObject(negate_result ? bool_true : bool_false); | 1397 __ PushObject(negate_result ? bool_true : bool_false); |
| 1339 } | 1398 } |
| 1340 } | 1399 } |
| 1341 return; | 1400 return; |
| 1342 } | 1401 } |
| 1343 | 1402 |
| 1403 Label is_instance_of, is_not_instance_of; |
| 1344 const Immediate raw_null = | 1404 const Immediate raw_null = |
| 1345 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1405 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1346 Label done, check_negate_done; | 1406 Label done; |
| 1347 // If type is instantiated and non-parameterized, we can inline code | 1407 // If type is instantiated and non-parameterized, we can inline code |
| 1348 // checking whether the tested instance is a Smi. | 1408 // checking whether the tested instance is a Smi. |
| 1349 if (type.IsInstantiated()) { | 1409 if (type.IsInstantiated()) { |
| 1350 // A null object is only an instance of Object and Dynamic, which has | 1410 // A null object is only an instance of Object and Dynamic, which has |
| 1351 // already been checked above (if the type is instantiated). So we can | 1411 // already been checked above (if the type is instantiated). So we can |
| 1352 // return false here if the instance is null (and if the type is | 1412 // return false here if the instance is null (and if the type is |
| 1353 // instantiated). | 1413 // instantiated). |
| 1354 // We can only inline this null check if the type is instantiated at compile | 1414 // We can only inline this null check if the type is instantiated at compile |
| 1355 // time, since an uninstantiated type at compile time could be Object or | 1415 // time, since an uninstantiated type at compile time could be Object or |
| 1356 // Dynamic at run time. | 1416 // Dynamic at run time. |
| 1357 Label non_null; | 1417 Label non_null; |
| 1358 __ cmpl(EAX, raw_null); | 1418 __ cmpl(EAX, raw_null); |
| 1359 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); | 1419 __ j(NOT_EQUAL, &non_null, Assembler::kNearJump); |
| 1360 __ PushObject(negate_result ? bool_true : bool_false); | 1420 __ PushObject(negate_result ? bool_true : bool_false); |
| 1361 __ jmp(&done, Assembler::kNearJump); | 1421 __ jmp(&done); |
| 1422 __ Bind(&non_null); |
| 1423 } |
| 1362 | 1424 |
| 1363 __ Bind(&non_null); | 1425 GenerateInlineInstanceof(node_id, token_index, type, |
| 1426 &is_instance_of, &is_not_instance_of); |
| 1364 | 1427 |
| 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 } | |
| 1477 } | |
| 1478 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1428 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1479 const Immediate location = | 1429 const Immediate location = |
| 1480 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | 1430 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1481 const Immediate node_id_as_smi = | 1431 const Immediate node_id_as_smi = |
| 1482 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id))); | 1432 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id))); |
| 1483 __ pushl(location); // Push the source location. | 1433 __ pushl(location); // Push the source location. |
| 1484 __ pushl(node_id_as_smi); // node-id. | 1434 __ pushl(node_id_as_smi); // node-id. |
| 1485 __ pushl(EAX); // Push the instance. | 1435 __ pushl(EAX); // Push the instance. |
| 1486 __ PushObject(type); // Push the type. | 1436 __ PushObject(type); // Push the type. |
| 1487 if (!type.IsInstantiated()) { | 1437 if (!type.IsInstantiated()) { |
| 1488 GenerateInstantiatorTypeArguments(token_index); | 1438 GenerateInstantiatorTypeArguments(token_index); |
| 1489 } else { | 1439 } else { |
| 1490 __ pushl(raw_null); // Null instantiator. | 1440 __ pushl(raw_null); // Null instantiator. |
| 1491 } | 1441 } |
| 1492 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1442 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1493 // Pop the two parameters supplied to the runtime entry. The result of the | 1443 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1494 // instanceof runtime call will be left as the result of the operation. | 1444 // instanceof runtime call will be left as the result of the operation. |
| 1495 __ addl(ESP, Immediate(5 * kWordSize)); | 1445 __ addl(ESP, Immediate(5 * kWordSize)); |
| 1496 __ Bind(&check_negate_done); | |
| 1497 if (negate_result) { | 1446 if (negate_result) { |
| 1498 Label negate_done; | |
| 1499 __ popl(EDX); | 1447 __ popl(EDX); |
| 1500 __ LoadObject(EAX, bool_true); | 1448 __ CompareObject(EDX, bool_false); |
| 1501 __ cmpl(EDX, EAX); | 1449 __ j(EQUAL, &is_not_instance_of, Assembler::kNearJump); |
| 1502 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1450 // Fall through to is_instance_of. |
| 1503 __ LoadObject(EAX, bool_false); | 1451 } else { |
| 1504 __ Bind(&negate_done); | 1452 __ jmp(&done); |
| 1505 __ pushl(EAX); | 1453 } |
| 1506 } | 1454 |
| 1455 __ Bind(&is_instance_of); |
| 1456 __ PushObject(negate_result ? bool_false: bool_true); |
| 1457 __ jmp(&done, Assembler::kNearJump); |
| 1458 __ Bind(&is_not_instance_of); |
| 1459 __ PushObject(negate_result ? bool_true: bool_false); |
| 1507 __ Bind(&done); | 1460 __ Bind(&done); |
| 1508 } | 1461 } |
| 1509 | 1462 |
| 1510 | 1463 |
| 1511 // Jumps to label if ECX equals the given class. | 1464 // EAX: instance to test. |
| 1512 // Inputs: | 1465 // Clobbers: ECX. |
| 1513 // - ECX: tested class. | 1466 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
| 1514 void CodeGenerator::TestClassAndJump(const Class& cls, Label* label) { | 1467 // type test is conclusive, otherwise fallthrough if a type test could not |
| 1515 __ CompareObject(ECX, cls); | 1468 // be completed. |
| 1516 __ j(EQUAL, label, Assembler::kNearJump); | 1469 void CodeGenerator::GenerateInstantiatedTypeWithArgumentsTest( |
| 1470 const AbstractType& type, |
| 1471 Label* is_instance_lbl, |
| 1472 Label* is_not_instance_lbl) { |
| 1473 ASSERT(type.IsInstantiated()); |
| 1474 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1475 ASSERT(type_class.HasTypeArguments()); |
| 1476 // A Smi object cannot be the instance of a parameterized class. |
| 1477 // A class equality check is only applicable with a dst type of a |
| 1478 // non-parameterized class or with a raw dst type of a parameterized class. |
| 1479 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1480 __ j(ZERO, is_not_instance_lbl); |
| 1481 const AbstractTypeArguments& type_arguments = |
| 1482 AbstractTypeArguments::Handle(type.arguments()); |
| 1483 const bool is_raw_type = type_arguments.IsNull() || |
| 1484 type_arguments.IsRaw(type_arguments.Length()); |
| 1485 if (is_raw_type) { |
| 1486 // Dynamic type argument, check only classes. |
| 1487 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1488 if (type.IsListInterface()) { |
| 1489 // TODO(srdjan) also accept List<Object>. |
| 1490 __ CompareObject(ECX, *CoreClass("ObjectArray")); |
| 1491 __ j(EQUAL, is_instance_lbl); |
| 1492 __ CompareObject(ECX, *CoreClass("GrowableObjectArray")); |
| 1493 __ j(EQUAL, is_instance_lbl); |
| 1494 } else if (!type_class.is_interface()) { |
| 1495 __ CompareObject(ECX, type_class); |
| 1496 __ j(EQUAL, is_instance_lbl); |
| 1497 } |
| 1498 } else { |
| 1499 // TODO(srdjan): do type test on type arguments. |
| 1500 } |
| 1501 // Fall through if type test is not conclusive |
| 1502 } |
| 1503 |
| 1504 |
| 1505 // EAX: instance to test. |
| 1506 // Clobbers: EBX, ECX, EDX. |
| 1507 void CodeGenerator::GenerateInstantiatedTypeNoArgumentsTest( |
| 1508 intptr_t node_id, |
| 1509 intptr_t token_index, |
| 1510 const AbstractType& type, |
| 1511 Label* is_instance_lbl, |
| 1512 Label* is_not_instance_lbl) { |
| 1513 ASSERT(type.IsInstantiated()); |
| 1514 const Class& type_class = Class::ZoneHandle(type.type_class()); |
| 1515 ASSERT(!type_class.HasTypeArguments()); |
| 1516 |
| 1517 Label compare_classes; |
| 1518 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1519 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1520 // Instance is Smi, check directly. |
| 1521 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1522 // TODO(regis): We should introduce a SmiType. |
| 1523 Error& malformed_error = Error::Handle(); |
| 1524 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1525 type_class, |
| 1526 TypeArguments::Handle(), |
| 1527 &malformed_error)) { |
| 1528 __ jmp(is_instance_lbl); |
| 1529 } else { |
| 1530 __ jmp(is_not_instance_lbl); |
| 1531 } |
| 1532 // Compare if the classes are equal. |
| 1533 __ Bind(&compare_classes); |
| 1534 |
| 1535 // Checking against interface. |
| 1536 // However, for specific core library interfaces, we can check for |
| 1537 // specific core library classes. |
| 1538 if (type.IsBoolInterface()) { |
| 1539 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1540 const Class& bool_class = Class::ZoneHandle( |
| 1541 Isolate::Current()->object_store()->bool_class()); |
| 1542 __ CompareObject(ECX, bool_class); |
| 1543 __ j(EQUAL, is_instance_lbl); |
| 1544 return; |
| 1545 } |
| 1546 // If type is an interface, we can skip the class equality check, |
| 1547 // because instances cannot be of an interface type. |
| 1548 if (!type_class.is_interface()) { |
| 1549 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1550 __ CompareObject(ECX, type_class); |
| 1551 __ j(EQUAL, is_instance_lbl); |
| 1552 } |
| 1553 if (type.IsSubtypeOf( |
| 1554 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 1555 // Custom checking for numbers (Smi, Mint, Bigint and Double) |
| 1556 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1557 if (type.IsIntInterface() || type.IsNumberInterface()) { |
| 1558 // We already checked for Smi above. |
| 1559 const Class& mint_class = Class::ZoneHandle( |
| 1560 Isolate::Current()->object_store()->mint_class()); |
| 1561 const Class& bigint_class = Class::ZoneHandle( |
| 1562 Isolate::Current()->object_store()->bigint_class()); |
| 1563 __ CompareObject(ECX, mint_class); |
| 1564 __ j(EQUAL, is_instance_lbl); |
| 1565 __ CompareObject(ECX, bigint_class); |
| 1566 __ j(EQUAL, is_instance_lbl); |
| 1567 } |
| 1568 if (type.IsDoubleInterface() || type.IsNumberInterface()) { |
| 1569 const Class& double_class = Class::ZoneHandle( |
| 1570 Isolate::Current()->object_store()->double_class()); |
| 1571 __ CompareObject(ECX, double_class); |
| 1572 __ j(EQUAL, is_instance_lbl); |
| 1573 } |
| 1574 } else if (type.IsStringInterface()) { |
| 1575 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1576 const Class& one_byte_string_class = Class::ZoneHandle( |
| 1577 Isolate::Current()->object_store()->one_byte_string_class()); |
| 1578 const Class& two_byte_string_class = Class::ZoneHandle( |
| 1579 Isolate::Current()->object_store()->two_byte_string_class()); |
| 1580 const Class& four_byte_string_class = Class::ZoneHandle( |
| 1581 Isolate::Current()->object_store()->four_byte_string_class()); |
| 1582 __ CompareObject(ECX, one_byte_string_class); |
| 1583 __ j(EQUAL, is_instance_lbl); |
| 1584 __ CompareObject(ECX, two_byte_string_class); |
| 1585 __ j(EQUAL, is_instance_lbl); |
| 1586 __ CompareObject(ECX, four_byte_string_class); |
| 1587 __ j(EQUAL, is_instance_lbl); |
| 1588 } else if (type.IsFunctionInterface()) { |
| 1589 // Check if instance is a closure. |
| 1590 const Immediate raw_null = |
| 1591 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1592 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1593 __ movl(ECX, FieldAddress(ECX, Class::signature_function_offset())); |
| 1594 __ cmpl(ECX, raw_null); |
| 1595 __ j(NOT_EQUAL, is_instance_lbl); |
| 1596 } |
| 1597 // Otherwise fallthrough. |
| 1598 } |
| 1599 |
| 1600 |
| 1601 // EAX: instance to test. |
| 1602 // Clobbers: EBX, EDX, ECX. |
| 1603 void CodeGenerator::GenerateUninstantiatedTypeTest( |
| 1604 const AbstractType& type, |
| 1605 intptr_t token_index, |
| 1606 Label* is_instance_lbl) { |
| 1607 ASSERT(!type.IsInstantiated()); |
| 1608 // Skip check if destination is a dynamic type. |
| 1609 if (type.IsTypeParameter()) { |
| 1610 const Immediate raw_null = |
| 1611 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1612 // EAX must be preserved! |
| 1613 Label fall_through; |
| 1614 GenerateInstantiatorTypeArguments(token_index); |
| 1615 // Type arguments are on stack. |
| 1616 __ popl(EBX); |
| 1617 // Check if type argument is dynamic. |
| 1618 __ cmpl(EBX, raw_null); |
| 1619 __ j(EQUAL, is_instance_lbl); |
| 1620 |
| 1621 // For now handle only TypeArguments and bail out if InstantiatedTypeArgs. |
| 1622 __ movl(EDX, FieldAddress(EBX, Object::class_offset())); |
| 1623 __ CompareObject(EDX, Object::ZoneHandle(Object::type_arguments_class())); |
| 1624 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1625 |
| 1626 // EBX: Instance of TypeArguments. |
| 1627 __ movl(EDX, |
| 1628 FieldAddress(EBX, TypeArguments::type_at_offset(type.Index()))); |
| 1629 // EDX: concrete type of type. |
| 1630 // Check if type argument is dynamic. |
| 1631 __ CompareObject(EDX, Type::ZoneHandle(Type::DynamicType())); |
| 1632 __ j(EQUAL, is_instance_lbl); |
| 1633 |
| 1634 // Check if the type has type parameters, if not do the class comparison. |
| 1635 Label not_smi; |
| 1636 __ testl(EAX, Immediate(kSmiTagMask)); // Value is Smi? |
| 1637 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 1638 // For Smi check quickly against int and num interfaces. |
| 1639 __ CompareObject(EDX, Type::ZoneHandle(Type::IntInterface())); |
| 1640 __ j(EQUAL, is_instance_lbl); |
| 1641 __ CompareObject(EDX, Type::ZoneHandle(Type::NumberInterface())); |
| 1642 __ j(EQUAL, is_instance_lbl); |
| 1643 __ jmp(&fall_through); |
| 1644 |
| 1645 __ Bind(¬_smi); |
| 1646 // The instantiated type parameter may not be a Type, but could be an |
| 1647 // InstantiatedType. It is therefore necessary to check its class. |
| 1648 __ movl(ECX, FieldAddress(EDX, Object::class_offset())); |
| 1649 __ CompareObject(ECX, Object::ZoneHandle(Object::type_class())); |
| 1650 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1651 |
| 1652 __ movl(EDX, FieldAddress(EDX, Type::type_class_offset())); |
| 1653 __ movl(ECX, FieldAddress(EDX, Class::type_parameters_offset())); |
| 1654 // Check that class of type has no type parameters. |
| 1655 __ cmpl(ECX, raw_null); |
| 1656 __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump); |
| 1657 // We have a non-parameterized class in EDX, compare with class of |
| 1658 // value in EAX. EAX, EDX are preserved in stub. |
| 1659 __ call(&StubCode::IsRawSubTypeLabel()); |
| 1660 // Result in EBX: 1 is raw subtype. |
| 1661 __ cmpl(EBX, Immediate(1)); |
| 1662 __ j(EQUAL, is_instance_lbl); |
| 1663 |
| 1664 // Test not conclusive. |
| 1665 __ Bind(&fall_through); |
| 1666 } |
| 1517 } | 1667 } |
| 1518 | 1668 |
| 1519 | 1669 |
| 1520 // If type check cannot be performed successfully at compile time and therefore | 1670 // If type check cannot be performed successfully at compile time and therefore |
| 1521 // eliminated, optimize it by adding inlined tests for: | 1671 // eliminated, optimize it by adding inlined tests for: |
| 1522 // - NULL -> return NULL. | 1672 // - NULL -> return NULL. |
| 1523 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 1673 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 1524 // - Class equality (only if class is not parameterized). | 1674 // - Class equality (only if class is not parameterized). |
| 1525 // Inputs: | 1675 // Inputs: |
| 1526 // - EAX: object. | 1676 // - EAX: object. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1595 __ PushObject(dst_name); // Push the name of the destination. | 1745 __ PushObject(dst_name); // Push the name of the destination. |
| 1596 __ PushObject(error_message); | 1746 __ PushObject(error_message); |
| 1597 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); | 1747 GenerateCallRuntime(node_id, token_index, kMalformedTypeErrorRuntimeEntry); |
| 1598 // We should never return here. | 1748 // We should never return here. |
| 1599 __ int3(); | 1749 __ int3(); |
| 1600 | 1750 |
| 1601 __ Bind(&done); // For a null object. | 1751 __ Bind(&done); // For a null object. |
| 1602 return; | 1752 return; |
| 1603 } | 1753 } |
| 1604 | 1754 |
| 1605 // If dst_type is instantiated and non-parameterized, we can inline code | 1755 GenerateInlineInstanceof(node_id, token_index, dst_type, |
| 1606 // checking whether the assigned instance is a Smi. | 1756 &done, &runtime_call); |
| 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); | |
| 1733 | 1757 |
| 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, ¬_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(¬_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 } | |
| 1772 __ Bind(&runtime_call); | 1758 __ Bind(&runtime_call); |
| 1773 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1759 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1774 const Immediate location = | 1760 const Immediate location = |
| 1775 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | 1761 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1762 const Immediate node_id_as_smi = |
| 1763 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id))); |
| 1776 __ pushl(location); // Push the source location. | 1764 __ pushl(location); // Push the source location. |
| 1765 __ pushl(node_id_as_smi); // node-id. |
| 1777 __ pushl(EAX); // Push the source object. | 1766 __ pushl(EAX); // Push the source object. |
| 1778 __ PushObject(dst_type); // Push the type of the destination. | 1767 __ PushObject(dst_type); // Push the type of the destination. |
| 1779 if (dst_type.IsInstantiated()) { | 1768 if (dst_type.IsInstantiated()) { |
| 1780 __ pushl(raw_null); // Null instantiator. | 1769 __ pushl(raw_null); // Null instantiator. |
| 1781 } else { | 1770 } else { |
| 1782 GenerateInstantiatorTypeArguments(token_index); | 1771 GenerateInstantiatorTypeArguments(token_index); |
| 1783 } | 1772 } |
| 1784 __ PushObject(dst_name); // Push the name of the destination. | 1773 __ PushObject(dst_name); // Push the name of the destination. |
| 1785 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); | 1774 GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry); |
| 1786 // Pop the parameters supplied to the runtime entry. The result of the | 1775 // Pop the parameters supplied to the runtime entry. The result of the |
| 1787 // type check runtime call is the checked value. | 1776 // type check runtime call is the checked value. |
| 1788 __ addl(ESP, Immediate(5 * kWordSize)); | 1777 __ addl(ESP, Immediate(6 * kWordSize)); |
| 1789 __ popl(EAX); | 1778 __ popl(EAX); |
| 1790 | 1779 |
| 1791 // EAX: value. | 1780 // EAX: value. |
| 1792 __ Bind(&done); | 1781 __ Bind(&done); |
| 1793 } | 1782 } |
| 1794 | 1783 |
| 1795 | 1784 |
| 1796 void CodeGenerator::GenerateArgumentTypeChecks() { | 1785 void CodeGenerator::GenerateArgumentTypeChecks() { |
| 1797 const Function& function = parsed_function_.function(); | 1786 const Function& function = parsed_function_.function(); |
| 1798 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); | 1787 const SequenceNode& sequence_node = *parsed_function_.node_sequence(); |
| (...skipping 1093 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2892 const Error& error = Error::Handle( | 2881 const Error& error = Error::Handle( |
| 2893 Parser::FormatError(script, token_index, "Error", format, args)); | 2882 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2894 va_end(args); | 2883 va_end(args); |
| 2895 Isolate::Current()->long_jump_base()->Jump(1, error); | 2884 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2896 UNREACHABLE(); | 2885 UNREACHABLE(); |
| 2897 } | 2886 } |
| 2898 | 2887 |
| 2899 } // namespace dart | 2888 } // namespace dart |
| 2900 | 2889 |
| 2901 #endif // defined TARGET_ARCH_IA32 | 2890 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |