| 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 1292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1303 Type::Handle(Isolate::Current()->object_store()->object_type()); | 1303 Type::Handle(Isolate::Current()->object_store()->object_type()); |
| 1304 Error& malformed_error = Error::Handle(); | 1304 Error& malformed_error = Error::Handle(); |
| 1305 if (type.IsInstantiated() && | 1305 if (type.IsInstantiated() && |
| 1306 object_type.IsSubtypeOf(type, &malformed_error)) { | 1306 object_type.IsSubtypeOf(type, &malformed_error)) { |
| 1307 __ PushObject(negate_result ? bool_false : bool_true); | 1307 __ PushObject(negate_result ? bool_false : bool_true); |
| 1308 return; | 1308 return; |
| 1309 } | 1309 } |
| 1310 | 1310 |
| 1311 const Immediate raw_null = | 1311 const Immediate raw_null = |
| 1312 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 1312 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1313 Label done; | 1313 Label done, check_negate_done; |
| 1314 // If type is instantiated and non-parameterized, we can inline code | 1314 // If type is instantiated and non-parameterized, we can inline code |
| 1315 // checking whether the tested instance is a Smi. | 1315 // checking whether the tested instance is a Smi. |
| 1316 if (type.IsInstantiated()) { | 1316 if (type.IsInstantiated()) { |
| 1317 // A null object is only an instance of Object and Dynamic, which has | 1317 // A null object is only an instance of Object and Dynamic, which has |
| 1318 // already been checked above (if the type is instantiated). So we can | 1318 // already been checked above (if the type is instantiated). So we can |
| 1319 // return false here if the instance is null (and if the type is | 1319 // return false here if the instance is null (and if the type is |
| 1320 // instantiated). | 1320 // instantiated). |
| 1321 // We can only inline this null check if the type is instantiated at compile | 1321 // We can only inline this null check if the type is instantiated at compile |
| 1322 // time, since an uninstantiated type at compile time could be Object or | 1322 // time, since an uninstantiated type at compile time could be Object or |
| 1323 // Dynamic at run time. | 1323 // Dynamic at run time. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1359 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1359 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1360 __ CompareObject(ECX, type_class); | 1360 __ CompareObject(ECX, type_class); |
| 1361 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1361 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1362 __ PushObject(negate_result ? bool_false : bool_true); | 1362 __ PushObject(negate_result ? bool_false : bool_true); |
| 1363 __ jmp(&done, Assembler::kNearJump); | 1363 __ jmp(&done, Assembler::kNearJump); |
| 1364 } | 1364 } |
| 1365 } | 1365 } |
| 1366 __ Bind(&runtime_call); | 1366 __ Bind(&runtime_call); |
| 1367 // Fall through to runtime call. | 1367 // Fall through to runtime call. |
| 1368 } else { | 1368 } else { |
| 1369 ASSERT(!requires_type_arguments); |
| 1370 // Test if object is Smi and for a couple known test-classes. |
| 1369 Label compare_classes; | 1371 Label compare_classes; |
| 1370 __ testl(EAX, Immediate(kSmiTagMask)); | 1372 __ testl(EAX, Immediate(kSmiTagMask)); |
| 1371 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); | 1373 __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump); |
| 1372 // Object is Smi. | 1374 // Object is Smi. |
| 1373 const Class& smi_class = Class::Handle(Smi::Class()); | 1375 const Class& smi_class = Class::Handle(Smi::Class()); |
| 1374 // TODO(regis): We should introduce a SmiType. | 1376 // TODO(regis): We should introduce a SmiType. |
| 1375 Error& malformed_error = Error::Handle(); | 1377 Error& malformed_error = Error::Handle(); |
| 1376 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), | 1378 if (smi_class.IsSubtypeOf(TypeArguments::Handle(), |
| 1377 type_class, | 1379 type_class, |
| 1378 TypeArguments::Handle(), | 1380 TypeArguments::Handle(), |
| 1379 &malformed_error)) { | 1381 &malformed_error)) { |
| 1380 __ PushObject(negate_result ? bool_false : bool_true); | 1382 __ PushObject(negate_result ? bool_false : bool_true); |
| 1381 } else { | 1383 } else { |
| 1382 __ PushObject(negate_result ? bool_true : bool_false); | 1384 __ PushObject(negate_result ? bool_true : bool_false); |
| 1383 } | 1385 } |
| 1384 __ jmp(&done, Assembler::kNearJump); | 1386 __ jmp(&done, Assembler::kNearJump); |
| 1385 | 1387 |
| 1386 // Compare if the classes are equal. | 1388 // Compare if the classes are equal. |
| 1387 __ Bind(&compare_classes); | 1389 __ Bind(&compare_classes); |
| 1388 const Class* compare_class = NULL; | 1390 const Class* compare_class = NULL; |
| 1389 if (type.IsStringInterface()) { | 1391 if (type.IsStringInterface()) { |
| 1390 compare_class = &Class::ZoneHandle( | 1392 compare_class = &Class::ZoneHandle( |
| 1391 Isolate::Current()->object_store()->one_byte_string_class()); | 1393 Isolate::Current()->object_store()->one_byte_string_class()); |
| 1392 } else if (type.IsBoolInterface()) { | 1394 } else if (type.IsBoolInterface()) { |
| 1393 compare_class = &Class::ZoneHandle( | 1395 compare_class = &Class::ZoneHandle( |
| 1394 Isolate::Current()->object_store()->bool_class()); | 1396 Isolate::Current()->object_store()->bool_class()); |
| 1395 } else if (!type_class.is_interface()) { | 1397 } else if (!type_class.is_interface()) { |
| 1396 compare_class = &type_class; | 1398 // Use equality test in prolog of cache test. |
| 1399 compare_class = NULL; |
| 1397 } | 1400 } |
| 1398 if (compare_class != NULL) { | 1401 // EAX: instance being tested. |
| 1402 if (compare_class == NULL) { |
| 1403 // Optional quick equality check and then the type test cache test. |
| 1404 Label loop, runtime_call, found_in_cache, cache_test; |
| 1405 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1406 if (!type_class.is_interface()) { |
| 1407 // Class equality test first. |
| 1408 __ CompareObject(ECX, type_class); |
| 1409 __ j(NOT_EQUAL, &cache_test, Assembler::kNearJump); |
| 1410 // Equal! |
| 1411 __ PushObject(negate_result ? bool_false : bool_true); |
| 1412 __ jmp(&done, Assembler::kNearJump); |
| 1413 } |
| 1414 __ Bind(&cache_test); |
| 1415 // TODO(srdjan): Convert other tests to this simple form. |
| 1416 // Class we are testing against has no type arguments. |
| 1417 // TODO(srdjan): Canonicalize initial array? |
| 1418 // TODO(srdjan): Account for 'negate_result' in cache. |
| 1419 // The type test array is null-terminated. Two consecutive |
| 1420 // array elements correspond to one test: |
| 1421 // array[i + 0] : class. |
| 1422 // array[i + 1] : result for the class. |
| 1423 AddCurrentDescriptor(PcDescriptors::kTypeTest, node_id, token_index); |
| 1424 __ LoadObject(EDX, Array::ZoneHandle(Array::New(2))); |
| 1425 __ addl(EDX, Immediate(Array::data_offset() - kHeapObjectTag)); |
| 1426 __ Bind(&loop); |
| 1427 __ movl(EBX, Address(EDX, 0)); |
| 1428 __ cmpl(ECX, EBX); |
| 1429 __ j(EQUAL, &found_in_cache, Assembler::kNearJump); |
| 1430 __ addl(EDX, Immediate(kWordSize * 2)); |
| 1431 __ cmpl(EBX, raw_null); |
| 1432 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1433 __ jmp(&runtime_call, Assembler::kNearJump); |
| 1434 __ Bind(&found_in_cache); |
| 1435 __ pushl(Address(EDX, kWordSize)); |
| 1436 __ jmp(&check_negate_done); |
| 1437 __ Bind(&runtime_call); |
| 1438 } else { |
| 1399 Label runtime_call; | 1439 Label runtime_call; |
| 1400 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); | 1440 __ movl(ECX, FieldAddress(EAX, Object::class_offset())); |
| 1401 __ CompareObject(ECX, *compare_class); | 1441 __ CompareObject(ECX, *compare_class); |
| 1402 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); | 1442 __ j(NOT_EQUAL, &runtime_call, Assembler::kNearJump); |
| 1403 __ PushObject(negate_result ? bool_false : bool_true); | 1443 __ PushObject(negate_result ? bool_false : bool_true); |
| 1404 __ jmp(&done, Assembler::kNearJump); | 1444 __ jmp(&done, Assembler::kNearJump); |
| 1405 __ Bind(&runtime_call); | 1445 __ Bind(&runtime_call); |
| 1406 } | 1446 } |
| 1407 } | 1447 } |
| 1408 } | 1448 } |
| 1409 __ PushObject(Object::ZoneHandle()); // Make room for the result. | 1449 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 1410 const Immediate location = | 1450 const Immediate location = |
| 1411 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); | 1451 Immediate(reinterpret_cast<int32_t>(Smi::New(token_index))); |
| 1452 const Immediate node_id_as_smi = |
| 1453 Immediate(reinterpret_cast<int32_t>(Smi::New(node_id))); |
| 1412 __ pushl(location); // Push the source location. | 1454 __ pushl(location); // Push the source location. |
| 1455 __ pushl(node_id_as_smi); // node-id. |
| 1413 __ pushl(EAX); // Push the instance. | 1456 __ pushl(EAX); // Push the instance. |
| 1414 __ PushObject(type); // Push the type. | 1457 __ PushObject(type); // Push the type. |
| 1415 if (!type.IsInstantiated()) { | 1458 if (!type.IsInstantiated()) { |
| 1416 GenerateInstantiatorTypeArguments(token_index); | 1459 GenerateInstantiatorTypeArguments(token_index); |
| 1417 } else { | 1460 } else { |
| 1418 __ pushl(raw_null); // Null instantiator. | 1461 __ pushl(raw_null); // Null instantiator. |
| 1419 } | 1462 } |
| 1420 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); | 1463 GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry); |
| 1421 // Pop the two parameters supplied to the runtime entry. The result of the | 1464 // Pop the two parameters supplied to the runtime entry. The result of the |
| 1422 // instanceof runtime call will be left as the result of the operation. | 1465 // instanceof runtime call will be left as the result of the operation. |
| 1423 __ addl(ESP, Immediate(4 * kWordSize)); | 1466 __ addl(ESP, Immediate(5 * kWordSize)); |
| 1467 __ Bind(&check_negate_done); |
| 1424 if (negate_result) { | 1468 if (negate_result) { |
| 1425 Label negate_done; | 1469 Label negate_done; |
| 1426 __ popl(EDX); | 1470 __ popl(EDX); |
| 1427 __ LoadObject(EAX, bool_true); | 1471 __ LoadObject(EAX, bool_true); |
| 1428 __ cmpl(EDX, EAX); | 1472 __ cmpl(EDX, EAX); |
| 1429 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); | 1473 __ j(NOT_EQUAL, &negate_done, Assembler::kNearJump); |
| 1430 __ LoadObject(EAX, bool_false); | 1474 __ LoadObject(EAX, bool_false); |
| 1431 __ Bind(&negate_done); | 1475 __ Bind(&negate_done); |
| 1432 __ pushl(EAX); | 1476 __ pushl(EAX); |
| 1433 } | 1477 } |
| (...skipping 1355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2789 const Error& error = Error::Handle( | 2833 const Error& error = Error::Handle( |
| 2790 Parser::FormatError(script, token_index, "Error", format, args)); | 2834 Parser::FormatError(script, token_index, "Error", format, args)); |
| 2791 va_end(args); | 2835 va_end(args); |
| 2792 Isolate::Current()->long_jump_base()->Jump(1, error); | 2836 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2793 UNREACHABLE(); | 2837 UNREACHABLE(); |
| 2794 } | 2838 } |
| 2795 | 2839 |
| 2796 } // namespace dart | 2840 } // namespace dart |
| 2797 | 2841 |
| 2798 #endif // defined TARGET_ARCH_IA32 | 2842 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |