| 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 |