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 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 456 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
457 intptr_t token_pos, | 457 intptr_t token_pos, |
458 const AbstractType& type, | 458 const AbstractType& type, |
459 Label* is_instance_lbl, | 459 Label* is_instance_lbl, |
460 Label* is_not_instance_lbl) { | 460 Label* is_not_instance_lbl) { |
461 __ Comment("UninstantiatedTypeTest"); | 461 __ Comment("UninstantiatedTypeTest"); |
462 ASSERT(!type.IsInstantiated()); | 462 ASSERT(!type.IsInstantiated()); |
463 // Skip check if destination is a dynamic type. | 463 // Skip check if destination is a dynamic type. |
464 if (type.IsTypeParameter()) { | 464 if (type.IsTypeParameter()) { |
465 const TypeParameter& type_param = TypeParameter::Cast(type); | 465 const TypeParameter& type_param = TypeParameter::Cast(type); |
466 // Load instantiator (or null) and instantiator type arguments on stack. | 466 // Load instantiator type arguments on stack. |
467 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 467 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
468 // RDX: instantiator type arguments. | 468 // RDX: instantiator type arguments. |
469 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 469 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
470 __ CompareObject(RDX, Object::null_object()); | 470 __ CompareObject(RDX, Object::null_object()); |
471 __ j(EQUAL, is_instance_lbl); | 471 __ j(EQUAL, is_instance_lbl); |
472 __ movq(RDI, | 472 __ movq(RDI, |
473 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); | 473 FieldAddress(RDX, TypeArguments::type_at_offset(type_param.index()))); |
474 // RDI: Concrete type of type. | 474 // RDI: Concrete type of type. |
475 // Check if type argument is dynamic. | 475 // Check if type argument is dynamic. |
476 __ CompareObject(RDI, Object::dynamic_type()); | 476 __ CompareObject(RDI, Object::dynamic_type()); |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 | 582 |
583 | 583 |
584 // If instanceof type test cannot be performed successfully at compile time and | 584 // If instanceof type test cannot be performed successfully at compile time and |
585 // therefore eliminated, optimize it by adding inlined tests for: | 585 // therefore eliminated, optimize it by adding inlined tests for: |
586 // - NULL -> return false. | 586 // - NULL -> return false. |
587 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 587 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
588 // - Class equality (only if class is not parameterized). | 588 // - Class equality (only if class is not parameterized). |
589 // Inputs: | 589 // Inputs: |
590 // - RAX: object. | 590 // - RAX: object. |
591 // - RDX: instantiator type arguments or raw_null. | 591 // - RDX: instantiator type arguments or raw_null. |
592 // - RCX: instantiator or raw_null. | 592 // Clobbers RDX. |
593 // Clobbers RCX and RDX. | |
594 // Returns: | 593 // Returns: |
595 // - true or false in RAX. | 594 // - true or false in RAX. |
596 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 595 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
597 intptr_t deopt_id, | 596 intptr_t deopt_id, |
598 const AbstractType& type, | 597 const AbstractType& type, |
599 bool negate_result, | 598 bool negate_result, |
600 LocationSummary* locs) { | 599 LocationSummary* locs) { |
601 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); | 600 ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
602 | 601 |
603 Label is_instance, is_not_instance; | 602 Label is_instance, is_not_instance; |
604 __ pushq(RCX); // Store instantiator on stack. | |
605 __ pushq(RDX); // Store instantiator type arguments. | 603 __ pushq(RDX); // Store instantiator type arguments. |
606 // If type is instantiated and non-parameterized, we can inline code | 604 // If type is instantiated and non-parameterized, we can inline code |
607 // checking whether the tested instance is a Smi. | 605 // checking whether the tested instance is a Smi. |
608 if (type.IsInstantiated()) { | 606 if (type.IsInstantiated()) { |
609 // A null object is only an instance of Object and dynamic, which has | 607 // A null object is only an instance of Object and dynamic, which has |
610 // already been checked above (if the type is instantiated). So we can | 608 // already been checked above (if the type is instantiated). So we can |
611 // return false here if the instance is null (and if the type is | 609 // return false here if the instance is null (and if the type is |
612 // instantiated). | 610 // instantiated). |
613 // We can only inline this null check if the type is instantiated at compile | 611 // We can only inline this null check if the type is instantiated at compile |
614 // time, since an uninstantiated type at compile time could be Object or | 612 // time, since an uninstantiated type at compile time could be Object or |
615 // dynamic at run time. | 613 // dynamic at run time. |
616 __ CompareObject(RAX, Object::null_object()); | 614 __ CompareObject(RAX, Object::null_object()); |
617 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); | 615 __ j(EQUAL, type.IsNullType() ? &is_instance : &is_not_instance); |
618 } | 616 } |
619 | 617 |
620 // Generate inline instanceof test. | 618 // Generate inline instanceof test. |
621 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 619 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
622 test_cache = GenerateInlineInstanceof(token_pos, type, | 620 test_cache = GenerateInlineInstanceof(token_pos, type, |
623 &is_instance, &is_not_instance); | 621 &is_instance, &is_not_instance); |
624 | 622 |
625 // test_cache is null if there is no fall-through. | 623 // test_cache is null if there is no fall-through. |
626 Label done; | 624 Label done; |
627 if (!test_cache.IsNull()) { | 625 if (!test_cache.IsNull()) { |
628 // Generate runtime call. | 626 // Generate runtime call. |
629 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 627 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
630 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | |
631 __ PushObject(Object::null_object()); // Make room for the result. | 628 __ PushObject(Object::null_object()); // Make room for the result. |
632 __ pushq(RAX); // Push the instance. | 629 __ pushq(RAX); // Push the instance. |
633 __ PushObject(type); // Push the type. | 630 __ PushObject(type); // Push the type. |
634 __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. | |
635 __ pushq(RDX); // Instantiator type arguments. | 631 __ pushq(RDX); // Instantiator type arguments. |
636 __ LoadUniqueObject(RAX, test_cache); | 632 __ LoadUniqueObject(RAX, test_cache); |
637 __ pushq(RAX); | 633 __ pushq(RAX); |
638 GenerateRuntimeCall(token_pos, | 634 GenerateRuntimeCall(token_pos, |
639 deopt_id, | 635 deopt_id, |
640 kInstanceofRuntimeEntry, | 636 kInstanceofRuntimeEntry, |
641 5, | 637 4, |
642 locs); | 638 locs); |
643 // Pop the parameters supplied to the runtime entry. The result of the | 639 // Pop the parameters supplied to the runtime entry. The result of the |
644 // instanceof runtime call will be left as the result of the operation. | 640 // instanceof runtime call will be left as the result of the operation. |
645 __ Drop(5); | 641 __ Drop(4); |
646 if (negate_result) { | 642 if (negate_result) { |
647 __ popq(RDX); | 643 __ popq(RDX); |
648 __ LoadObject(RAX, Bool::True()); | 644 __ LoadObject(RAX, Bool::True()); |
649 __ cmpq(RDX, RAX); | 645 __ cmpq(RDX, RAX); |
650 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | 646 __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
651 __ LoadObject(RAX, Bool::False()); | 647 __ LoadObject(RAX, Bool::False()); |
652 } else { | 648 } else { |
653 __ popq(RAX); | 649 __ popq(RAX); |
654 } | 650 } |
655 __ jmp(&done, Assembler::kNearJump); | 651 __ jmp(&done, Assembler::kNearJump); |
656 } | 652 } |
657 __ Bind(&is_not_instance); | 653 __ Bind(&is_not_instance); |
658 __ LoadObject(RAX, Bool::Get(negate_result)); | 654 __ LoadObject(RAX, Bool::Get(negate_result)); |
659 __ jmp(&done, Assembler::kNearJump); | 655 __ jmp(&done, Assembler::kNearJump); |
660 | 656 |
661 __ Bind(&is_instance); | 657 __ Bind(&is_instance); |
662 __ LoadObject(RAX, Bool::Get(!negate_result)); | 658 __ LoadObject(RAX, Bool::Get(!negate_result)); |
663 __ Bind(&done); | 659 __ Bind(&done); |
664 __ popq(RDX); // Remove pushed instantiator type arguments. | 660 __ popq(RDX); // Remove pushed instantiator type arguments. |
665 __ popq(RCX); // Remove pushed instantiator. | |
666 } | 661 } |
667 | 662 |
668 | 663 |
669 // Optimize assignable type check by adding inlined tests for: | 664 // Optimize assignable type check by adding inlined tests for: |
670 // - NULL -> return NULL. | 665 // - NULL -> return NULL. |
671 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 666 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
672 // - Class equality (only if class is not parameterized). | 667 // - Class equality (only if class is not parameterized). |
673 // Inputs: | 668 // Inputs: |
674 // - RAX: object. | 669 // - RAX: object. |
675 // - RDX: instantiator type arguments or raw_null. | 670 // - RDX: instantiator type arguments or raw_null. |
676 // - RCX: instantiator or raw_null. | |
677 // Returns: | 671 // Returns: |
678 // - object in RAX for successful assignable check (or throws TypeError). | 672 // - object in RAX for successful assignable check (or throws TypeError). |
679 // Performance notes: positive checks must be quick, negative checks can be slow | 673 // Performance notes: positive checks must be quick, negative checks can be slow |
680 // as they throw an exception. | 674 // as they throw an exception. |
681 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 675 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
682 intptr_t deopt_id, | 676 intptr_t deopt_id, |
683 const AbstractType& dst_type, | 677 const AbstractType& dst_type, |
684 const String& dst_name, | 678 const String& dst_name, |
685 LocationSummary* locs) { | 679 LocationSummary* locs) { |
686 ASSERT(token_pos >= 0); | 680 ASSERT(token_pos >= 0); |
687 ASSERT(!dst_type.IsNull()); | 681 ASSERT(!dst_type.IsNull()); |
688 ASSERT(dst_type.IsFinalized()); | 682 ASSERT(dst_type.IsFinalized()); |
689 // Assignable check is skipped in FlowGraphBuilder, not here. | 683 // Assignable check is skipped in FlowGraphBuilder, not here. |
690 ASSERT(dst_type.IsMalformedOrMalbounded() || | 684 ASSERT(dst_type.IsMalformedOrMalbounded() || |
691 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 685 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
692 __ pushq(RCX); // Store instantiator. | |
693 __ pushq(RDX); // Store instantiator type arguments. | 686 __ pushq(RDX); // Store instantiator type arguments. |
694 // A null object is always assignable and is returned as result. | 687 // A null object is always assignable and is returned as result. |
695 Label is_assignable, runtime_call; | 688 Label is_assignable, runtime_call; |
696 __ CompareObject(RAX, Object::null_object()); | 689 __ CompareObject(RAX, Object::null_object()); |
697 __ j(EQUAL, &is_assignable); | 690 __ j(EQUAL, &is_assignable); |
698 | 691 |
699 // Generate throw new TypeError() if the type is malformed or malbounded. | 692 // Generate throw new TypeError() if the type is malformed or malbounded. |
700 if (dst_type.IsMalformedOrMalbounded()) { | 693 if (dst_type.IsMalformedOrMalbounded()) { |
701 __ PushObject(Object::null_object()); // Make room for the result. | 694 __ PushObject(Object::null_object()); // Make room for the result. |
702 __ pushq(RAX); // Push the source object. | 695 __ pushq(RAX); // Push the source object. |
703 __ PushObject(dst_name); // Push the name of the destination. | 696 __ PushObject(dst_name); // Push the name of the destination. |
704 __ PushObject(dst_type); // Push the type of the destination. | 697 __ PushObject(dst_type); // Push the type of the destination. |
705 GenerateRuntimeCall(token_pos, | 698 GenerateRuntimeCall(token_pos, |
706 deopt_id, | 699 deopt_id, |
707 kBadTypeErrorRuntimeEntry, | 700 kBadTypeErrorRuntimeEntry, |
708 3, | 701 3, |
709 locs); | 702 locs); |
710 // We should never return here. | 703 // We should never return here. |
711 __ int3(); | 704 __ int3(); |
712 | 705 |
713 __ Bind(&is_assignable); // For a null object. | 706 __ Bind(&is_assignable); // For a null object. |
714 __ popq(RDX); // Remove pushed instantiator type arguments. | 707 __ popq(RDX); // Remove pushed instantiator type arguments. |
715 __ popq(RCX); // Remove pushed instantiator. | |
716 return; | 708 return; |
717 } | 709 } |
718 | 710 |
719 // Generate inline type check, linking to runtime call if not assignable. | 711 // Generate inline type check, linking to runtime call if not assignable. |
720 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 712 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
721 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 713 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
722 &is_assignable, &runtime_call); | 714 &is_assignable, &runtime_call); |
723 | 715 |
724 __ Bind(&runtime_call); | 716 __ Bind(&runtime_call); |
725 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. | 717 __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
726 __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator. | |
727 __ PushObject(Object::null_object()); // Make room for the result. | 718 __ PushObject(Object::null_object()); // Make room for the result. |
728 __ pushq(RAX); // Push the source object. | 719 __ pushq(RAX); // Push the source object. |
729 __ PushObject(dst_type); // Push the type of the destination. | 720 __ PushObject(dst_type); // Push the type of the destination. |
730 __ pushq(RCX); // Instantiator. | |
731 __ pushq(RDX); // Instantiator type arguments. | 721 __ pushq(RDX); // Instantiator type arguments. |
732 __ PushObject(dst_name); // Push the name of the destination. | 722 __ PushObject(dst_name); // Push the name of the destination. |
733 __ LoadUniqueObject(RAX, test_cache); | 723 __ LoadUniqueObject(RAX, test_cache); |
734 __ pushq(RAX); | 724 __ pushq(RAX); |
735 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 725 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
736 // Pop the parameters supplied to the runtime entry. The result of the | 726 // Pop the parameters supplied to the runtime entry. The result of the |
737 // type check runtime call is the checked value. | 727 // type check runtime call is the checked value. |
738 __ Drop(6); | 728 __ Drop(5); |
739 __ popq(RAX); | 729 __ popq(RAX); |
740 | 730 |
741 __ Bind(&is_assignable); | 731 __ Bind(&is_assignable); |
742 __ popq(RDX); // Remove pushed instantiator type arguments. | 732 __ popq(RDX); // Remove pushed instantiator type arguments. |
743 __ popq(RCX); // Remove pushed instantiator. | |
744 } | 733 } |
745 | 734 |
746 | 735 |
747 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 736 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
748 if (is_optimizing()) { | 737 if (is_optimizing()) { |
749 return; | 738 return; |
750 } | 739 } |
751 Definition* defn = instr->AsDefinition(); | 740 Definition* defn = instr->AsDefinition(); |
752 if ((defn != NULL) && defn->HasTemp()) { | 741 if ((defn != NULL) && defn->HasTemp()) { |
753 Location value = defn->locs()->out(0); | 742 Location value = defn->locs()->out(0); |
(...skipping 1067 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1821 __ movups(reg, Address(RSP, 0)); | 1810 __ movups(reg, Address(RSP, 0)); |
1822 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); | 1811 __ AddImmediate(RSP, Immediate(kFpuRegisterSize)); |
1823 } | 1812 } |
1824 | 1813 |
1825 | 1814 |
1826 #undef __ | 1815 #undef __ |
1827 | 1816 |
1828 } // namespace dart | 1817 } // namespace dart |
1829 | 1818 |
1830 #endif // defined TARGET_ARCH_X64 | 1819 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |