OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 __ j(EQUAL, is_true); | 198 __ j(EQUAL, is_true); |
199 __ jmp(is_false); | 199 __ jmp(is_false); |
200 __ Bind(&fall_through); | 200 __ Bind(&fall_through); |
201 } | 201 } |
202 | 202 |
203 | 203 |
204 // Clobbers RCX. | 204 // Clobbers RCX. |
205 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( | 205 RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
206 TypeTestStubKind test_kind, | 206 TypeTestStubKind test_kind, |
207 Register instance_reg, | 207 Register instance_reg, |
208 Register type_arguments_reg, | 208 Register instantiator_type_arguments_reg, |
| 209 Register function_type_arguments_reg, |
209 Register temp_reg, | 210 Register temp_reg, |
210 Label* is_instance_lbl, | 211 Label* is_instance_lbl, |
211 Label* is_not_instance_lbl) { | 212 Label* is_not_instance_lbl) { |
212 const SubtypeTestCache& type_test_cache = | 213 const SubtypeTestCache& type_test_cache = |
213 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); | 214 SubtypeTestCache::ZoneHandle(zone(), SubtypeTestCache::New()); |
214 __ LoadUniqueObject(temp_reg, type_test_cache); | 215 __ LoadUniqueObject(temp_reg, type_test_cache); |
215 __ pushq(temp_reg); // Subtype test cache. | 216 __ pushq(temp_reg); // Subtype test cache. |
216 __ pushq(instance_reg); // Instance. | 217 __ pushq(instance_reg); // Instance. |
217 if (test_kind == kTestTypeOneArg) { | 218 if (test_kind == kTestTypeOneArg) { |
218 ASSERT(type_arguments_reg == kNoRegister); | 219 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
219 __ PushObject(Object::null_object()); | 220 ASSERT(function_type_arguments_reg == kNoRegister); |
| 221 __ PushObject(Object::null_object()); // Unused instantiator type args. |
| 222 __ PushObject(Object::null_object()); // Unused function type args. |
220 __ Call(*StubCode::Subtype1TestCache_entry()); | 223 __ Call(*StubCode::Subtype1TestCache_entry()); |
221 } else if (test_kind == kTestTypeTwoArgs) { | 224 } else if (test_kind == kTestTypeTwoArgs) { |
222 ASSERT(type_arguments_reg == kNoRegister); | 225 ASSERT(instantiator_type_arguments_reg == kNoRegister); |
223 __ PushObject(Object::null_object()); | 226 ASSERT(function_type_arguments_reg == kNoRegister); |
| 227 __ PushObject(Object::null_object()); // Unused instantiator type args. |
| 228 __ PushObject(Object::null_object()); // Unused function type args. |
224 __ Call(*StubCode::Subtype2TestCache_entry()); | 229 __ Call(*StubCode::Subtype2TestCache_entry()); |
225 } else if (test_kind == kTestTypeThreeArgs) { | 230 } else if (test_kind == kTestTypeFourArgs) { |
226 __ pushq(type_arguments_reg); | 231 __ pushq(instantiator_type_arguments_reg); |
227 __ Call(*StubCode::Subtype3TestCache_entry()); | 232 __ pushq(function_type_arguments_reg); |
| 233 __ Call(*StubCode::Subtype4TestCache_entry()); |
228 } else { | 234 } else { |
229 UNREACHABLE(); | 235 UNREACHABLE(); |
230 } | 236 } |
231 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. | 237 // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False. |
232 ASSERT(instance_reg != RCX); | 238 ASSERT(instance_reg != RCX); |
233 ASSERT(temp_reg != RCX); | 239 ASSERT(temp_reg != RCX); |
234 __ popq(instance_reg); // Discard. | 240 __ Drop(2); |
235 __ popq(instance_reg); // Restore receiver. | 241 __ popq(instance_reg); // Restore receiver. |
236 __ popq(temp_reg); // Discard. | 242 __ popq(temp_reg); // Discard. |
237 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); | 243 GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); |
238 return type_test_cache.raw(); | 244 return type_test_cache.raw(); |
239 } | 245 } |
240 | 246 |
241 | 247 |
242 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if | 248 // Jumps to labels 'is_instance' or 'is_not_instance' respectively, if |
243 // type test is conclusive, otherwise fallthrough if a type test could not | 249 // type test is conclusive, otherwise fallthrough if a type test could not |
244 // be completed. | 250 // be completed. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); | 306 const Type& object_type = Type::Handle(zone(), Type::ObjectType()); |
301 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { | 307 if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) { |
302 // Instance class test only necessary. | 308 // Instance class test only necessary. |
303 return GenerateSubtype1TestCacheLookup( | 309 return GenerateSubtype1TestCacheLookup( |
304 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); | 310 token_pos, type_class, is_instance_lbl, is_not_instance_lbl); |
305 } | 311 } |
306 } | 312 } |
307 } | 313 } |
308 } | 314 } |
309 // Regular subtype test cache involving instance's type arguments. | 315 // Regular subtype test cache involving instance's type arguments. |
310 const Register kTypeArgumentsReg = kNoRegister; | 316 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 317 const Register kFunctionTypeArgumentsReg = kNoRegister; |
311 const Register kTempReg = R10; | 318 const Register kTempReg = R10; |
312 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, | 319 return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
313 kTypeArgumentsReg, kTempReg, | 320 kInstantiatorTypeArgumentsReg, |
| 321 kFunctionTypeArgumentsReg, kTempReg, |
314 is_instance_lbl, is_not_instance_lbl); | 322 is_instance_lbl, is_not_instance_lbl); |
315 } | 323 } |
316 | 324 |
317 | 325 |
318 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, | 326 void FlowGraphCompiler::CheckClassIds(Register class_id_reg, |
319 const GrowableArray<intptr_t>& class_ids, | 327 const GrowableArray<intptr_t>& class_ids, |
320 Label* is_equal_lbl, | 328 Label* is_equal_lbl, |
321 Label* is_not_equal_lbl) { | 329 Label* is_not_equal_lbl) { |
322 for (intptr_t i = 0; i < class_ids.length(); i++) { | 330 for (intptr_t i = 0; i < class_ids.length(); i++) { |
323 __ cmpl(class_id_reg, Immediate(class_ids[i])); | 331 __ cmpl(class_id_reg, Immediate(class_ids[i])); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 __ Comment("Subtype1TestCacheLookup"); | 418 __ Comment("Subtype1TestCacheLookup"); |
411 const Register kInstanceReg = RAX; | 419 const Register kInstanceReg = RAX; |
412 __ LoadClass(R10, kInstanceReg); | 420 __ LoadClass(R10, kInstanceReg); |
413 // R10: instance class. | 421 // R10: instance class. |
414 // Check immediate superclass equality. | 422 // Check immediate superclass equality. |
415 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); | 423 __ movq(R13, FieldAddress(R10, Class::super_type_offset())); |
416 __ movq(R13, FieldAddress(R13, Type::type_class_id_offset())); | 424 __ movq(R13, FieldAddress(R13, Type::type_class_id_offset())); |
417 __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id()))); | 425 __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id()))); |
418 __ j(EQUAL, is_instance_lbl); | 426 __ j(EQUAL, is_instance_lbl); |
419 | 427 |
420 const Register kTypeArgumentsReg = kNoRegister; | 428 const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| 429 const Register kFunctionTypeArgumentsReg = kNoRegister; |
421 const Register kTempReg = R10; | 430 const Register kTempReg = R10; |
422 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, | 431 return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
423 kTypeArgumentsReg, kTempReg, | 432 kInstantiatorTypeArgumentsReg, |
| 433 kFunctionTypeArgumentsReg, kTempReg, |
424 is_instance_lbl, is_not_instance_lbl); | 434 is_instance_lbl, is_not_instance_lbl); |
425 } | 435 } |
426 | 436 |
427 | 437 |
428 // Generates inlined check if 'type' is a type parameter or type itself | 438 // Generates inlined check if 'type' is a type parameter or type itself |
429 // RAX: instance (preserved). | 439 // RAX: instance (preserved). |
430 // Clobbers RDI, RDX, R10. | 440 // Clobbers RDI, RDX, R10. |
431 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 441 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
432 TokenPosition token_pos, | 442 TokenPosition token_pos, |
433 const AbstractType& type, | 443 const AbstractType& type, |
434 Label* is_instance_lbl, | 444 Label* is_instance_lbl, |
435 Label* is_not_instance_lbl) { | 445 Label* is_not_instance_lbl) { |
436 __ Comment("UninstantiatedTypeTest"); | 446 __ Comment("UninstantiatedTypeTest"); |
437 ASSERT(!type.IsInstantiated()); | 447 ASSERT(!type.IsInstantiated()); |
438 // Skip check if destination is a dynamic type. | 448 // Skip check if destination is a dynamic type. |
439 if (type.IsTypeParameter()) { | 449 if (type.IsTypeParameter()) { |
440 const TypeParameter& type_param = TypeParameter::Cast(type); | 450 const TypeParameter& type_param = TypeParameter::Cast(type); |
441 // Load instantiator type arguments on stack. | 451 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. |
442 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 452 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. |
443 // RDX: instantiator type arguments. | 453 // RDX: instantiator type arguments. |
| 454 // RCX: function type arguments. |
| 455 const Register kTypeArgumentsReg = |
| 456 type_param.IsClassTypeParameter() ? RDX : RCX; |
444 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 457 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
445 __ CompareObject(RDX, Object::null_object()); | 458 __ CompareObject(kTypeArgumentsReg, Object::null_object()); |
446 __ j(EQUAL, is_instance_lbl); | 459 __ j(EQUAL, is_instance_lbl); |
447 __ movq(RDI, FieldAddress( | 460 __ movq(RDI, FieldAddress(kTypeArgumentsReg, TypeArguments::type_at_offset( |
448 RDX, TypeArguments::type_at_offset(type_param.index()))); | 461 type_param.index()))); |
449 // RDI: Concrete type of type. | 462 // RDI: Concrete type of type. |
450 // Check if type argument is dynamic. | 463 // Check if type argument is dynamic. |
451 __ CompareObject(RDI, Object::dynamic_type()); | 464 __ CompareObject(RDI, Object::dynamic_type()); |
452 __ j(EQUAL, is_instance_lbl); | 465 __ j(EQUAL, is_instance_lbl); |
453 const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType()); | 466 const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType()); |
454 __ CompareObject(RDI, object_type); | 467 __ CompareObject(RDI, object_type); |
455 __ j(EQUAL, is_instance_lbl); | 468 __ j(EQUAL, is_instance_lbl); |
| 469 // TODO(regis): Optimize void type as well once allowed as type argument. |
456 | 470 |
457 // For Smi check quickly against int and num interfaces. | 471 // For Smi check quickly against int and num interfaces. |
458 Label not_smi; | 472 Label not_smi; |
459 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? | 473 __ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi? |
460 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | 474 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
461 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType())); | 475 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::IntType())); |
462 __ j(EQUAL, is_instance_lbl); | 476 __ j(EQUAL, is_instance_lbl); |
463 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number())); | 477 __ CompareObject(RDI, Type::ZoneHandle(zone(), Type::Number())); |
464 __ j(EQUAL, is_instance_lbl); | 478 __ j(EQUAL, is_instance_lbl); |
465 // Smi must be handled in runtime. | 479 // Smi must be handled in runtime. |
466 Label fall_through; | 480 Label fall_through; |
467 __ jmp(&fall_through); | 481 __ jmp(&fall_through); |
468 | 482 |
469 __ Bind(¬_smi); | 483 __ Bind(¬_smi); |
| 484 // RAX: instance. |
470 // RDX: instantiator type arguments. | 485 // RDX: instantiator type arguments. |
471 // RAX: instance. | 486 // RCX: function type arguments. |
472 const Register kInstanceReg = RAX; | 487 const Register kInstanceReg = RAX; |
473 const Register kTypeArgumentsReg = RDX; | 488 const Register kInstantiatorTypeArgumentsReg = RDX; |
| 489 const Register kFunctionTypeArgumentsReg = RCX; |
474 const Register kTempReg = R10; | 490 const Register kTempReg = R10; |
475 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( | 491 const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
476 zone(), GenerateCallSubtypeTestStub( | 492 zone(), GenerateCallSubtypeTestStub( |
477 kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, | 493 kTestTypeFourArgs, kInstanceReg, |
| 494 kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, |
478 kTempReg, is_instance_lbl, is_not_instance_lbl)); | 495 kTempReg, is_instance_lbl, is_not_instance_lbl)); |
479 __ Bind(&fall_through); | 496 __ Bind(&fall_through); |
480 return type_test_cache.raw(); | 497 return type_test_cache.raw(); |
481 } | 498 } |
482 if (type.IsType()) { | 499 if (type.IsType()) { |
483 const Register kInstanceReg = RAX; | 500 const Register kInstanceReg = RAX; |
484 const Register kTypeArgumentsReg = RDX; | 501 const Register kInstantiatorTypeArgumentsReg = RDX; |
| 502 const Register kFunctionTypeArgumentsReg = RCX; |
485 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? | 503 __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
486 __ j(ZERO, is_not_instance_lbl); | 504 __ j(ZERO, is_not_instance_lbl); |
487 __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args. | 505 __ movq(kInstantiatorTypeArgumentsReg, Address(RSP, 1 * kWordSize)); |
| 506 __ movq(kFunctionTypeArgumentsReg, Address(RSP, 0 * kWordSize)); |
488 // Uninstantiated type class is known at compile time, but the type | 507 // Uninstantiated type class is known at compile time, but the type |
489 // arguments are determined at runtime by the instantiator. | 508 // arguments are determined at runtime by the instantiator(s). |
490 const Register kTempReg = R10; | 509 const Register kTempReg = R10; |
491 return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, | 510 return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
492 kTypeArgumentsReg, kTempReg, | 511 kInstantiatorTypeArgumentsReg, |
| 512 kFunctionTypeArgumentsReg, kTempReg, |
493 is_instance_lbl, is_not_instance_lbl); | 513 is_instance_lbl, is_not_instance_lbl); |
494 } | 514 } |
495 return SubtypeTestCache::null(); | 515 return SubtypeTestCache::null(); |
496 } | 516 } |
497 | 517 |
498 | 518 |
499 // Inputs: | 519 // Inputs: |
500 // - RAX: instance to test against (preserved). | 520 // - RAX: instance to test against (preserved). |
501 // - RDX: optional instantiator type arguments (preserved). | 521 // - RDX: optional instantiator type arguments (preserved). |
| 522 // - RCX: optional function type arguments (preserved). |
502 // Clobbers R10, R13. | 523 // Clobbers R10, R13. |
503 // Returns: | 524 // Returns: |
504 // - preserved instance in RAX and optional instantiator type arguments in RDX. | 525 // - preserved instance in RAX, optional instantiator type arguments in RDX, and |
| 526 // optional function type arguments in RCX. |
505 // Note that this inlined code must be followed by the runtime_call code, as it | 527 // Note that this inlined code must be followed by the runtime_call code, as it |
506 // may fall through to it. Otherwise, this inline code will jump to the label | 528 // may fall through to it. Otherwise, this inline code will jump to the label |
507 // is_instance or to the label is_not_instance. | 529 // is_instance or to the label is_not_instance. |
508 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( | 530 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
509 TokenPosition token_pos, | 531 TokenPosition token_pos, |
510 const AbstractType& type, | 532 const AbstractType& type, |
511 Label* is_instance_lbl, | 533 Label* is_instance_lbl, |
512 Label* is_not_instance_lbl) { | 534 Label* is_not_instance_lbl) { |
513 __ Comment("InlineInstanceof"); | 535 __ Comment("InlineInstanceof"); |
514 if (type.IsVoidType()) { | 536 if (type.IsVoidType()) { |
(...skipping 28 matching lines...) Expand all Loading... |
543 | 565 |
544 | 566 |
545 // If instanceof type test cannot be performed successfully at compile time and | 567 // If instanceof type test cannot be performed successfully at compile time and |
546 // therefore eliminated, optimize it by adding inlined tests for: | 568 // therefore eliminated, optimize it by adding inlined tests for: |
547 // - NULL -> return type == Null (type is not Object or dynamic). | 569 // - NULL -> return type == Null (type is not Object or dynamic). |
548 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 570 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
549 // - Class equality (only if class is not parameterized). | 571 // - Class equality (only if class is not parameterized). |
550 // Inputs: | 572 // Inputs: |
551 // - RAX: object. | 573 // - RAX: object. |
552 // - RDX: instantiator type arguments or raw_null. | 574 // - RDX: instantiator type arguments or raw_null. |
553 // Clobbers RDX. | 575 // - RCX: function type arguments or raw_null. |
554 // Returns: | 576 // Returns: |
555 // - true or false in RAX. | 577 // - true or false in RAX. |
556 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, | 578 void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
557 intptr_t deopt_id, | 579 intptr_t deopt_id, |
558 const AbstractType& type, | 580 const AbstractType& type, |
559 LocationSummary* locs) { | 581 LocationSummary* locs) { |
560 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 582 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
561 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); | 583 ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
562 | 584 |
| 585 __ pushq(RDX); // Store instantiator type arguments. |
| 586 __ pushq(RCX); // Store function type arguments. |
| 587 |
563 Label is_instance, is_not_instance; | 588 Label is_instance, is_not_instance; |
564 __ pushq(RDX); // Store instantiator type arguments. | |
565 // If type is instantiated and non-parameterized, we can inline code | 589 // If type is instantiated and non-parameterized, we can inline code |
566 // checking whether the tested instance is a Smi. | 590 // checking whether the tested instance is a Smi. |
567 if (type.IsInstantiated()) { | 591 if (type.IsInstantiated()) { |
568 // A null object is only an instance of Null, Object, and dynamic. | 592 // A null object is only an instance of Null, Object, and dynamic. |
569 // Object and dynamic have already been checked above (if the type is | 593 // Object and dynamic have already been checked above (if the type is |
570 // instantiated). So we can return false here if the instance is null, | 594 // instantiated). So we can return false here if the instance is null, |
571 // unless the type is Null (and if the type is instantiated). | 595 // unless the type is Null (and if the type is instantiated). |
572 // We can only inline this null check if the type is instantiated at compile | 596 // We can only inline this null check if the type is instantiated at compile |
573 // time, since an uninstantiated type at compile time could be Null, Object, | 597 // time, since an uninstantiated type at compile time could be Null, Object, |
574 // or dynamic at run time. | 598 // or dynamic at run time. |
575 __ CompareObject(RAX, Object::null_object()); | 599 __ CompareObject(RAX, Object::null_object()); |
576 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 600 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
577 } | 601 } |
578 | 602 |
579 // Generate inline instanceof test. | 603 // Generate inline instanceof test. |
580 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 604 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
581 test_cache = | 605 test_cache = |
582 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); | 606 GenerateInlineInstanceof(token_pos, type, &is_instance, &is_not_instance); |
583 | 607 |
584 // test_cache is null if there is no fall-through. | 608 // test_cache is null if there is no fall-through. |
585 Label done; | 609 Label done; |
586 if (!test_cache.IsNull()) { | 610 if (!test_cache.IsNull()) { |
587 // Generate runtime call. | 611 // Generate runtime call. |
588 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 612 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. |
| 613 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. |
589 __ PushObject(Object::null_object()); // Make room for the result. | 614 __ PushObject(Object::null_object()); // Make room for the result. |
590 __ pushq(RAX); // Push the instance. | 615 __ pushq(RAX); // Push the instance. |
591 __ PushObject(type); // Push the type. | 616 __ PushObject(type); // Push the type. |
592 __ pushq(RDX); // Instantiator type arguments. | 617 __ pushq(RDX); // Instantiator type arguments. |
| 618 __ pushq(RCX); // Function type arguments. |
593 __ LoadUniqueObject(RAX, test_cache); | 619 __ LoadUniqueObject(RAX, test_cache); |
594 __ pushq(RAX); | 620 __ pushq(RAX); |
595 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); | 621 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
596 // Pop the parameters supplied to the runtime entry. The result of the | 622 // Pop the parameters supplied to the runtime entry. The result of the |
597 // instanceof runtime call will be left as the result of the operation. | 623 // instanceof runtime call will be left as the result of the operation. |
598 __ Drop(4); | 624 __ Drop(5); |
599 __ popq(RAX); | 625 __ popq(RAX); |
600 __ jmp(&done, Assembler::kNearJump); | 626 __ jmp(&done, Assembler::kNearJump); |
601 } | 627 } |
602 __ Bind(&is_not_instance); | 628 __ Bind(&is_not_instance); |
603 __ LoadObject(RAX, Bool::Get(false)); | 629 __ LoadObject(RAX, Bool::Get(false)); |
604 __ jmp(&done, Assembler::kNearJump); | 630 __ jmp(&done, Assembler::kNearJump); |
605 | 631 |
606 __ Bind(&is_instance); | 632 __ Bind(&is_instance); |
607 __ LoadObject(RAX, Bool::Get(true)); | 633 __ LoadObject(RAX, Bool::Get(true)); |
608 __ Bind(&done); | 634 __ Bind(&done); |
| 635 __ popq(RCX); // Remove pushed function type arguments. |
609 __ popq(RDX); // Remove pushed instantiator type arguments. | 636 __ popq(RDX); // Remove pushed instantiator type arguments. |
610 } | 637 } |
611 | 638 |
612 | 639 |
613 // Optimize assignable type check by adding inlined tests for: | 640 // Optimize assignable type check by adding inlined tests for: |
614 // - NULL -> return NULL. | 641 // - NULL -> return NULL. |
615 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 642 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
616 // - Class equality (only if class is not parameterized). | 643 // - Class equality (only if class is not parameterized). |
617 // Inputs: | 644 // Inputs: |
618 // - RAX: object. | 645 // - RAX: object. |
619 // - RDX: instantiator type arguments or raw_null. | 646 // - RDX: instantiator type arguments or raw_null. |
| 647 // - RCX: function type arguments or raw_null. |
620 // Returns: | 648 // Returns: |
621 // - object in RAX for successful assignable check (or throws TypeError). | 649 // - object in RAX for successful assignable check (or throws TypeError). |
622 // Performance notes: positive checks must be quick, negative checks can be slow | 650 // Performance notes: positive checks must be quick, negative checks can be slow |
623 // as they throw an exception. | 651 // as they throw an exception. |
624 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, | 652 void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
625 intptr_t deopt_id, | 653 intptr_t deopt_id, |
626 const AbstractType& dst_type, | 654 const AbstractType& dst_type, |
627 const String& dst_name, | 655 const String& dst_name, |
628 LocationSummary* locs) { | 656 LocationSummary* locs) { |
629 ASSERT(!token_pos.IsClassifying()); | 657 ASSERT(!token_pos.IsClassifying()); |
630 ASSERT(!dst_type.IsNull()); | 658 ASSERT(!dst_type.IsNull()); |
631 ASSERT(dst_type.IsFinalized()); | 659 ASSERT(dst_type.IsFinalized()); |
632 // Assignable check is skipped in FlowGraphBuilder, not here. | 660 // Assignable check is skipped in FlowGraphBuilder, not here. |
633 ASSERT(dst_type.IsMalformedOrMalbounded() || | 661 ASSERT(dst_type.IsMalformedOrMalbounded() || |
634 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 662 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
635 __ pushq(RDX); // Store instantiator type arguments. | 663 __ pushq(RDX); // Store instantiator type arguments. |
| 664 __ pushq(RCX); // Store function type arguments. |
636 // A null object is always assignable and is returned as result. | 665 // A null object is always assignable and is returned as result. |
637 Label is_assignable, runtime_call; | 666 Label is_assignable, runtime_call; |
638 __ CompareObject(RAX, Object::null_object()); | 667 __ CompareObject(RAX, Object::null_object()); |
639 __ j(EQUAL, &is_assignable); | 668 __ j(EQUAL, &is_assignable); |
640 | 669 |
641 // Generate throw new TypeError() if the type is malformed or malbounded. | 670 // Generate throw new TypeError() if the type is malformed or malbounded. |
642 if (dst_type.IsMalformedOrMalbounded()) { | 671 if (dst_type.IsMalformedOrMalbounded()) { |
643 __ PushObject(Object::null_object()); // Make room for the result. | 672 __ PushObject(Object::null_object()); // Make room for the result. |
644 __ pushq(RAX); // Push the source object. | 673 __ pushq(RAX); // Push the source object. |
645 __ PushObject(dst_name); // Push the name of the destination. | 674 __ PushObject(dst_name); // Push the name of the destination. |
646 __ PushObject(dst_type); // Push the type of the destination. | 675 __ PushObject(dst_type); // Push the type of the destination. |
647 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, | 676 GenerateRuntimeCall(token_pos, deopt_id, kBadTypeErrorRuntimeEntry, 3, |
648 locs); | 677 locs); |
649 // We should never return here. | 678 // We should never return here. |
650 __ int3(); | 679 __ int3(); |
651 | 680 |
652 __ Bind(&is_assignable); // For a null object. | 681 __ Bind(&is_assignable); // For a null object. |
| 682 __ popq(RCX); // Remove pushed function type arguments. |
653 __ popq(RDX); // Remove pushed instantiator type arguments. | 683 __ popq(RDX); // Remove pushed instantiator type arguments. |
654 return; | 684 return; |
655 } | 685 } |
656 | 686 |
657 // Generate inline type check, linking to runtime call if not assignable. | 687 // Generate inline type check, linking to runtime call if not assignable. |
658 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 688 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
659 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, | 689 test_cache = GenerateInlineInstanceof(token_pos, dst_type, &is_assignable, |
660 &runtime_call); | 690 &runtime_call); |
661 | 691 |
662 __ Bind(&runtime_call); | 692 __ Bind(&runtime_call); |
663 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 693 __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. |
| 694 __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. |
664 __ PushObject(Object::null_object()); // Make room for the result. | 695 __ PushObject(Object::null_object()); // Make room for the result. |
665 __ pushq(RAX); // Push the source object. | 696 __ pushq(RAX); // Push the source object. |
666 __ PushObject(dst_type); // Push the type of the destination. | 697 __ PushObject(dst_type); // Push the type of the destination. |
667 __ pushq(RDX); // Instantiator type arguments. | 698 __ pushq(RDX); // Instantiator type arguments. |
| 699 __ pushq(RCX); // Function type arguments. |
668 __ PushObject(dst_name); // Push the name of the destination. | 700 __ PushObject(dst_name); // Push the name of the destination. |
669 __ LoadUniqueObject(RAX, test_cache); | 701 __ LoadUniqueObject(RAX, test_cache); |
670 __ pushq(RAX); | 702 __ pushq(RAX); |
671 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); | 703 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
672 // Pop the parameters supplied to the runtime entry. The result of the | 704 // Pop the parameters supplied to the runtime entry. The result of the |
673 // type check runtime call is the checked value. | 705 // type check runtime call is the checked value. |
674 __ Drop(5); | 706 __ Drop(6); |
675 __ popq(RAX); | 707 __ popq(RAX); |
676 | 708 |
677 __ Bind(&is_assignable); | 709 __ Bind(&is_assignable); |
| 710 __ popq(RCX); // Remove pushed function type arguments. |
678 __ popq(RDX); // Remove pushed instantiator type arguments. | 711 __ popq(RDX); // Remove pushed instantiator type arguments. |
679 } | 712 } |
680 | 713 |
681 | 714 |
682 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 715 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
683 if (is_optimizing()) { | 716 if (is_optimizing()) { |
684 return; | 717 return; |
685 } | 718 } |
686 Definition* defn = instr->AsDefinition(); | 719 Definition* defn = instr->AsDefinition(); |
687 if ((defn != NULL) && defn->HasTemp()) { | 720 if ((defn != NULL) && defn->HasTemp()) { |
(...skipping 1073 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1761 __ movups(reg, Address(RSP, 0)); | 1794 __ movups(reg, Address(RSP, 0)); |
1762 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); | 1795 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); |
1763 } | 1796 } |
1764 | 1797 |
1765 | 1798 |
1766 #undef __ | 1799 #undef __ |
1767 | 1800 |
1768 } // namespace dart | 1801 } // namespace dart |
1769 | 1802 |
1770 #endif // defined TARGET_ARCH_X64 | 1803 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |