| 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/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 __ j(EQUAL, is_equal_lbl); | 211 __ j(EQUAL, is_equal_lbl); |
| 212 } | 212 } |
| 213 __ jmp(is_not_equal_lbl); | 213 __ jmp(is_not_equal_lbl); |
| 214 } | 214 } |
| 215 | 215 |
| 216 | 216 |
| 217 // Testing against an instantiated type with no arguments, without | 217 // Testing against an instantiated type with no arguments, without |
| 218 // SubtypeTestCache. | 218 // SubtypeTestCache. |
| 219 // RAX: instance to test against (preserved). | 219 // RAX: instance to test against (preserved). |
| 220 // Clobbers R10, R13. | 220 // Clobbers R10, R13. |
| 221 void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( | 221 // Returns true if there is a fallthrough. |
| 222 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest( |
| 222 intptr_t cid, | 223 intptr_t cid, |
| 223 intptr_t token_pos, | 224 intptr_t token_pos, |
| 224 const AbstractType& type, | 225 const AbstractType& type, |
| 225 Label* is_instance_lbl, | 226 Label* is_instance_lbl, |
| 226 Label* is_not_instance_lbl) { | 227 Label* is_not_instance_lbl) { |
| 227 ASSERT(type.IsInstantiated()); | 228 ASSERT(type.IsInstantiated()); |
| 228 const Class& type_class = Class::Handle(type.type_class()); | 229 const Class& type_class = Class::Handle(type.type_class()); |
| 229 ASSERT(!type_class.HasTypeArguments()); | 230 ASSERT(!type_class.HasTypeArguments()); |
| 230 | 231 |
| 231 const Register kInstanceReg = RAX; | 232 const Register kInstanceReg = RAX; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 251 if (!type_class.is_interface()) { | 252 if (!type_class.is_interface()) { |
| 252 __ cmpl(kClassIdReg, Immediate(type_class.id())); | 253 __ cmpl(kClassIdReg, Immediate(type_class.id())); |
| 253 __ j(EQUAL, is_instance_lbl); | 254 __ j(EQUAL, is_instance_lbl); |
| 254 } | 255 } |
| 255 // Bool interface can be implemented only by core class Bool. | 256 // Bool interface can be implemented only by core class Bool. |
| 256 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces). | 257 // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces). |
| 257 if (type.IsBoolInterface()) { | 258 if (type.IsBoolInterface()) { |
| 258 __ cmpl(kClassIdReg, Immediate(kBool)); | 259 __ cmpl(kClassIdReg, Immediate(kBool)); |
| 259 __ j(EQUAL, is_instance_lbl); | 260 __ j(EQUAL, is_instance_lbl); |
| 260 __ jmp(is_not_instance_lbl); | 261 __ jmp(is_not_instance_lbl); |
| 261 return; | 262 return false; |
| 262 } | 263 } |
| 263 if (type.IsFunctionInterface()) { | 264 if (type.IsFunctionInterface()) { |
| 264 // Check if instance is a closure. | 265 // Check if instance is a closure. |
| 265 const Immediate raw_null = | 266 const Immediate raw_null = |
| 266 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 267 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 267 __ LoadClassById(R13, kClassIdReg); | 268 __ LoadClassById(R13, kClassIdReg); |
| 268 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); | 269 __ movq(R13, FieldAddress(R13, Class::signature_function_offset())); |
| 269 __ cmpq(R13, raw_null); | 270 __ cmpq(R13, raw_null); |
| 270 __ j(NOT_EQUAL, is_instance_lbl); | 271 __ j(NOT_EQUAL, is_instance_lbl); |
| 271 __ jmp(is_not_instance_lbl); | 272 __ jmp(is_not_instance_lbl); |
| 272 return; | 273 return false; |
| 273 } | 274 } |
| 274 // Custom checking for numbers (Smi, Mint, Bigint and Double). | 275 // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| 275 // Note that instance is not Smi(checked above). | 276 // Note that instance is not Smi (checked above). |
| 276 if (type.IsSubtypeOf( | 277 if (type.IsSubtypeOf( |
| 277 Type::Handle(Type::NumberInterface()), &malformed_error)) { | 278 Type::Handle(Type::NumberInterface()), &malformed_error)) { |
| 278 GenerateNumberTypeCheck( | 279 GenerateNumberTypeCheck( |
| 279 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); | 280 kClassIdReg, type, is_instance_lbl, is_not_instance_lbl); |
| 280 return; | 281 return false; |
| 281 } | 282 } |
| 282 if (type.IsStringInterface()) { | 283 if (type.IsStringInterface()) { |
| 283 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); | 284 GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl); |
| 284 return; | 285 return false; |
| 285 } | 286 } |
| 286 // Otherwise fallthrough. | 287 // Otherwise fallthrough. |
| 288 return true; |
| 287 } | 289 } |
| 288 | 290 |
| 289 | 291 |
| 290 // Uses SubtypeTestCache to store instance class and result. | 292 // Uses SubtypeTestCache to store instance class and result. |
| 291 // RAX: instance to test. | 293 // RAX: instance to test. |
| 292 // Clobbers R10, R13. | 294 // Clobbers R10, R13. |
| 293 // Immediate class test already done. | 295 // Immediate class test already done. |
| 294 // TODO(srdjan): Implement a quicker subtype check, as type test | 296 // TODO(srdjan): Implement a quicker subtype check, as type test |
| 295 // arrays can grow too high, but they may be useful when optimizing | 297 // arrays can grow too high, but they may be useful when optimizing |
| 296 // code (type-feedback). | 298 // code (type-feedback). |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 // A class equality check is only applicable with a dst type of a | 434 // A class equality check is only applicable with a dst type of a |
| 433 // non-parameterized class or with a raw dst type of a parameterized class. | 435 // non-parameterized class or with a raw dst type of a parameterized class. |
| 434 if (type_class.HasTypeArguments()) { | 436 if (type_class.HasTypeArguments()) { |
| 435 return GenerateInstantiatedTypeWithArgumentsTest(cid, | 437 return GenerateInstantiatedTypeWithArgumentsTest(cid, |
| 436 token_pos, | 438 token_pos, |
| 437 type, | 439 type, |
| 438 is_instance_lbl, | 440 is_instance_lbl, |
| 439 is_not_instance_lbl); | 441 is_not_instance_lbl); |
| 440 // Fall through to runtime call. | 442 // Fall through to runtime call. |
| 441 } | 443 } |
| 442 GenerateInstantiatedTypeNoArgumentsTest(cid, | 444 const bool has_fall_through = |
| 443 token_pos, | 445 GenerateInstantiatedTypeNoArgumentsTest(cid, |
| 444 type, | 446 token_pos, |
| 445 is_instance_lbl, | 447 type, |
| 446 is_not_instance_lbl); | 448 is_instance_lbl, |
| 447 // If test non-conclusive so far, try the inlined type-test cache. | 449 is_not_instance_lbl); |
| 448 // 'type' is known at compile time. | 450 if (has_fall_through) { |
| 449 return GenerateSubtype1TestCacheLookup( | 451 // If test non-conclusive so far, try the inlined type-test cache. |
| 450 cid, token_pos, type_class, | 452 // 'type' is known at compile time. |
| 451 is_instance_lbl, is_not_instance_lbl); | 453 return GenerateSubtype1TestCacheLookup( |
| 454 cid, token_pos, type_class, |
| 455 is_instance_lbl, is_not_instance_lbl); |
| 456 } else { |
| 457 return SubtypeTestCache::null(); |
| 458 } |
| 452 } | 459 } |
| 453 return GenerateUninstantiatedTypeTest(cid, | 460 return GenerateUninstantiatedTypeTest(cid, |
| 454 token_pos, | 461 token_pos, |
| 455 type, | 462 type, |
| 456 is_instance_lbl, | 463 is_instance_lbl, |
| 457 is_not_instance_lbl); | 464 is_not_instance_lbl); |
| 458 } | 465 } |
| 459 | 466 |
| 460 | 467 |
| 461 // If instanceof type test cannot be performed successfully at compile time and | 468 // If instanceof type test cannot be performed successfully at compile time and |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 494 // Dynamic at run time. | 501 // Dynamic at run time. |
| 495 __ cmpq(RAX, raw_null); | 502 __ cmpq(RAX, raw_null); |
| 496 __ j(EQUAL, &is_not_instance); | 503 __ j(EQUAL, &is_not_instance); |
| 497 } | 504 } |
| 498 | 505 |
| 499 // Generate inline instanceof test. | 506 // Generate inline instanceof test. |
| 500 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); | 507 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(); |
| 501 test_cache = GenerateInlineInstanceof(cid, token_pos, type, | 508 test_cache = GenerateInlineInstanceof(cid, token_pos, type, |
| 502 &is_instance, &is_not_instance); | 509 &is_instance, &is_not_instance); |
| 503 | 510 |
| 504 // Generate runtime call. | 511 // test_cache is null if there is no fall-through. |
| 505 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | |
| 506 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | |
| 507 __ PushObject(Object::ZoneHandle()); // Make room for the result. | |
| 508 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. | |
| 509 __ pushq(RAX); // Push the instance. | |
| 510 __ PushObject(type); // Push the type. | |
| 511 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. | |
| 512 __ pushq(RDX); // Instantiator type arguments. | |
| 513 __ LoadObject(RAX, test_cache); | |
| 514 __ pushq(RAX); | |
| 515 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry); | |
| 516 // Pop the parameters supplied to the runtime entry. The result of the | |
| 517 // instanceof runtime call will be left as the result of the operation. | |
| 518 __ Drop(6); | |
| 519 Label done; | 512 Label done; |
| 520 if (negate_result) { | 513 if (!test_cache.IsNull()) { |
| 521 __ popq(RDX); | 514 // Generate runtime call. |
| 522 __ LoadObject(RAX, bool_true()); | 515 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| 523 __ cmpq(RDX, RAX); | 516 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. |
| 524 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 517 __ PushObject(Object::ZoneHandle()); // Make room for the result. |
| 525 __ LoadObject(RAX, bool_false()); | 518 __ pushq(Immediate(Smi::RawValue(cid))); // Computation id. |
| 526 } else { | 519 __ pushq(RAX); // Push the instance. |
| 527 __ popq(RAX); | 520 __ PushObject(type); // Push the type. |
| 521 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. |
| 522 __ pushq(RDX); // Instantiator type arguments. |
| 523 __ LoadObject(RAX, test_cache); |
| 524 __ pushq(RAX); |
| 525 GenerateCallRuntime(cid, token_pos, try_index, kInstanceofRuntimeEntry); |
| 526 // Pop the parameters supplied to the runtime entry. The result of the |
| 527 // instanceof runtime call will be left as the result of the operation. |
| 528 __ Drop(6); |
| 529 if (negate_result) { |
| 530 __ popq(RDX); |
| 531 __ LoadObject(RAX, bool_true()); |
| 532 __ cmpq(RDX, RAX); |
| 533 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| 534 __ LoadObject(RAX, bool_false()); |
| 535 } else { |
| 536 __ popq(RAX); |
| 537 } |
| 538 __ jmp(&done, Assembler::kNearJump); |
| 528 } | 539 } |
| 529 __ jmp(&done, Assembler::kNearJump); | |
| 530 | |
| 531 __ Bind(&is_not_instance); | 540 __ Bind(&is_not_instance); |
| 532 __ LoadObject(RAX, negate_result ? bool_true() : bool_false()); | 541 __ LoadObject(RAX, negate_result ? bool_true() : bool_false()); |
| 533 __ jmp(&done, Assembler::kNearJump); | 542 __ jmp(&done, Assembler::kNearJump); |
| 534 | 543 |
| 535 __ Bind(&is_instance); | 544 __ Bind(&is_instance); |
| 536 __ LoadObject(RAX, negate_result ? bool_false() : bool_true()); | 545 __ LoadObject(RAX, negate_result ? bool_false() : bool_true()); |
| 537 __ Bind(&done); | 546 __ Bind(&done); |
| 538 __ popq(RDX); // Remove pushed instantiator type arguments. | 547 __ popq(RDX); // Remove pushed instantiator type arguments. |
| 539 __ popq(RCX); // Remove pushed instantiator. | 548 __ popq(RCX); // Remove pushed instantiator. |
| 540 } | 549 } |
| (...skipping 601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1142 } | 1151 } |
| 1143 } | 1152 } |
| 1144 } | 1153 } |
| 1145 | 1154 |
| 1146 | 1155 |
| 1147 #undef __ | 1156 #undef __ |
| 1148 | 1157 |
| 1149 } // namespace dart | 1158 } // namespace dart |
| 1150 | 1159 |
| 1151 #endif // defined TARGET_ARCH_X64 | 1160 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |