| 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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 443 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| 444 intptr_t token_pos, | 444 intptr_t token_pos, |
| 445 const AbstractType& type, | 445 const AbstractType& type, |
| 446 Label* is_instance_lbl, | 446 Label* is_instance_lbl, |
| 447 Label* is_not_instance_lbl) { | 447 Label* is_not_instance_lbl) { |
| 448 __ Comment("UninstantiatedTypeTest"); | 448 __ Comment("UninstantiatedTypeTest"); |
| 449 ASSERT(!type.IsInstantiated()); | 449 ASSERT(!type.IsInstantiated()); |
| 450 // Skip check if destination is a dynamic type. | 450 // Skip check if destination is a dynamic type. |
| 451 if (type.IsTypeParameter()) { | 451 if (type.IsTypeParameter()) { |
| 452 const TypeParameter& type_param = TypeParameter::Cast(type); | 452 const TypeParameter& type_param = TypeParameter::Cast(type); |
| 453 // Load instantiator (or null) and instantiator type arguments on stack. | 453 // Load instantiator type arguments on stack. |
| 454 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. | 454 __ lw(A1, Address(SP, 0)); // Get instantiator type arguments. |
| 455 // A1: instantiator type arguments. | 455 // A1: instantiator type arguments. |
| 456 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 456 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| 457 __ LoadObject(T7, Object::null_object()); | 457 __ LoadObject(T7, Object::null_object()); |
| 458 __ beq(A1, T7, is_instance_lbl); | 458 __ beq(A1, T7, is_instance_lbl); |
| 459 __ lw(T2, | 459 __ lw(T2, |
| 460 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); | 460 FieldAddress(A1, TypeArguments::type_at_offset(type_param.index()))); |
| 461 // R2: concrete type of type. | 461 // R2: concrete type of type. |
| 462 // Check if type argument is dynamic. | 462 // Check if type argument is dynamic. |
| 463 __ BranchEqual(T2, | 463 __ BranchEqual(T2, |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 568 | 568 |
| 569 | 569 |
| 570 // If instanceof type test cannot be performed successfully at compile time and | 570 // If instanceof type test cannot be performed successfully at compile time and |
| 571 // therefore eliminated, optimize it by adding inlined tests for: | 571 // therefore eliminated, optimize it by adding inlined tests for: |
| 572 // - NULL -> return false. | 572 // - NULL -> return false. |
| 573 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 573 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 574 // - Class equality (only if class is not parameterized). | 574 // - Class equality (only if class is not parameterized). |
| 575 // Inputs: | 575 // Inputs: |
| 576 // - A0: object. | 576 // - A0: object. |
| 577 // - A1: instantiator type arguments or raw_null. | 577 // - A1: instantiator type arguments or raw_null. |
| 578 // - A2: instantiator or raw_null. | |
| 579 // Returns: | 578 // Returns: |
| 580 // - true or false in V0. | 579 // - true or false in V0. |
| 581 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 580 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
| 582 intptr_t deopt_id, | 581 intptr_t deopt_id, |
| 583 const AbstractType& type, | 582 const AbstractType& type, |
| 584 bool negate_result, | 583 bool negate_result, |
| 585 LocationSummary* locs) { | 584 LocationSummary* locs) { |
| 586 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 585 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
| 587 | 586 |
| 588 // Preserve instantiator (A2) and its type arguments (A1). | 587 // Preserve instantiator type arguments (A1). |
| 589 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 588 __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
| 590 __ sw(A2, Address(SP, 1 * kWordSize)); | |
| 591 __ sw(A1, Address(SP, 0 * kWordSize)); | 589 __ sw(A1, Address(SP, 0 * kWordSize)); |
| 592 | 590 |
| 593 Label is_instance, is_not_instance; | 591 Label is_instance, is_not_instance; |
| 594 // If type is instantiated and non-parameterized, we can inline code | 592 // If type is instantiated and non-parameterized, we can inline code |
| 595 // checking whether the tested instance is a Smi. | 593 // checking whether the tested instance is a Smi. |
| 596 if (type.IsInstantiated()) { | 594 if (type.IsInstantiated()) { |
| 597 // A null object is only an instance of Object and dynamic, which has | 595 // A null object is only an instance of Object and dynamic, which has |
| 598 // already been checked above (if the type is instantiated). So we can | 596 // already been checked above (if the type is instantiated). So we can |
| 599 // return false here if the instance is null (and if the type is | 597 // return false here if the instance is null (and if the type is |
| 600 // instantiated). | 598 // instantiated). |
| 601 // We can only inline this null check if the type is instantiated at compile | 599 // We can only inline this null check if the type is instantiated at compile |
| 602 // time, since an uninstantiated type at compile time could be Object or | 600 // time, since an uninstantiated type at compile time could be Object or |
| 603 // dynamic at run time. | 601 // dynamic at run time. |
| 604 __ BranchEqual(A0, Object::null_object(), | 602 __ BranchEqual(A0, Object::null_object(), |
| 605 type.IsNullType() ? &is_instance : &is_not_instance); | 603 type.IsNullType() ? &is_instance : &is_not_instance); |
| 606 } | 604 } |
| 607 | 605 |
| 608 // Generate inline instanceof test. | 606 // Generate inline instanceof test. |
| 609 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 607 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 610 test_cache = GenerateInlineInstanceof(token_pos, type, | 608 test_cache = GenerateInlineInstanceof(token_pos, type, |
| 611 &is_instance, &is_not_instance); | 609 &is_instance, &is_not_instance); |
| 612 | 610 |
| 613 // test_cache is null if there is no fall-through. | 611 // test_cache is null if there is no fall-through. |
| 614 Label done; | 612 Label done; |
| 615 if (!test_cache.IsNull()) { | 613 if (!test_cache.IsNull()) { |
| 616 // Generate runtime call. | 614 // Generate runtime call. |
| 617 // Load instantiator (A2) and its type arguments (A1). | 615 // Load instantiator type arguments (A1). |
| 618 __ lw(A1, Address(SP, 0 * kWordSize)); | 616 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 619 __ lw(A2, Address(SP, 1 * kWordSize)); | |
| 620 | 617 |
| 621 __ addiu(SP, SP, Immediate(-6 * kWordSize)); | 618 __ addiu(SP, SP, Immediate(-5 * kWordSize)); |
| 622 __ LoadObject(TMP, Object::null_object()); | 619 __ LoadObject(TMP, Object::null_object()); |
| 623 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. | 620 __ sw(TMP, Address(SP, 4 * kWordSize)); // Make room for the result. |
| 624 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the instance. | 621 __ sw(A0, Address(SP, 3 * kWordSize)); // Push the instance. |
| 625 __ LoadObject(TMP, type); | 622 __ LoadObject(TMP, type); |
| 626 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type. | 623 __ sw(TMP, Address(SP, 2 * kWordSize)); // Push the type. |
| 627 __ sw(A2, Address(SP, 2 * kWordSize)); // Push instantiator. | |
| 628 __ sw(A1, Address(SP, 1 * kWordSize)); // Push type arguments. | 624 __ sw(A1, Address(SP, 1 * kWordSize)); // Push type arguments. |
| 629 __ LoadUniqueObject(A0, test_cache); | 625 __ LoadUniqueObject(A0, test_cache); |
| 630 __ sw(A0, Address(SP, 0 * kWordSize)); | 626 __ sw(A0, Address(SP, 0 * kWordSize)); |
| 631 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); | 627 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
| 632 // Pop the parameters supplied to the runtime entry. The result of the | 628 // Pop the parameters supplied to the runtime entry. The result of the |
| 633 // instanceof runtime call will be left as the result of the operation. | 629 // instanceof runtime call will be left as the result of the operation. |
| 634 __ lw(T0, Address(SP, 5 * kWordSize)); | 630 __ lw(T0, Address(SP, 4 * kWordSize)); |
| 635 __ addiu(SP, SP, Immediate(6 * kWordSize)); | 631 __ addiu(SP, SP, Immediate(5 * kWordSize)); |
| 636 if (negate_result) { | 632 if (negate_result) { |
| 637 __ LoadObject(V0, Bool::True()); | 633 __ LoadObject(V0, Bool::True()); |
| 638 __ bne(T0, V0, &done); | 634 __ bne(T0, V0, &done); |
| 639 __ LoadObject(V0, Bool::False()); | 635 __ LoadObject(V0, Bool::False()); |
| 640 } else { | 636 } else { |
| 641 __ mov(V0, T0); | 637 __ mov(V0, T0); |
| 642 } | 638 } |
| 643 __ b(&done); | 639 __ b(&done); |
| 644 } | 640 } |
| 645 __ Bind(&is_not_instance); | 641 __ Bind(&is_not_instance); |
| 646 __ LoadObject(V0, Bool::Get(negate_result)); | 642 __ LoadObject(V0, Bool::Get(negate_result)); |
| 647 __ b(&done); | 643 __ b(&done); |
| 648 | 644 |
| 649 __ Bind(&is_instance); | 645 __ Bind(&is_instance); |
| 650 __ LoadObject(V0, Bool::Get(!negate_result)); | 646 __ LoadObject(V0, Bool::Get(!negate_result)); |
| 651 __ Bind(&done); | 647 __ Bind(&done); |
| 652 // Remove instantiator (A2) and its type arguments (A1). | 648 // Remove instantiator type arguments (A1). |
| 653 __ Drop(2); | 649 __ Drop(1); |
| 654 } | 650 } |
| 655 | 651 |
| 656 | 652 |
| 657 // Optimize assignable type check by adding inlined tests for: | 653 // Optimize assignable type check by adding inlined tests for: |
| 658 // - NULL -> return NULL. | 654 // - NULL -> return NULL. |
| 659 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 655 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
| 660 // - Class equality (only if class is not parameterized). | 656 // - Class equality (only if class is not parameterized). |
| 661 // Inputs: | 657 // Inputs: |
| 662 // - A0: instance being type checked. | 658 // - A0: instance being type checked. |
| 663 // - A1: instantiator type arguments or raw_null. | 659 // - A1: instantiator type arguments or raw_null. |
| 664 // - A2: instantiator or raw_null. | |
| 665 // Returns: | 660 // Returns: |
| 666 // - object in A0 for successful assignable check (or throws TypeError). | 661 // - object in A0 for successful assignable check (or throws TypeError). |
| 667 // Clobbers: T0, T1, T2 | 662 // Clobbers: T0, T1, T2 |
| 668 // Performance notes: positive checks must be quick, negative checks can be slow | 663 // Performance notes: positive checks must be quick, negative checks can be slow |
| 669 // as they throw an exception. | 664 // as they throw an exception. |
| 670 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 665 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
| 671 intptr_t deopt_id, | 666 intptr_t deopt_id, |
| 672 const AbstractType& dst_type, | 667 const AbstractType& dst_type, |
| 673 const String& dst_name, | 668 const String& dst_name, |
| 674 LocationSummary* locs) { | 669 LocationSummary* locs) { |
| 675 __ Comment("AssertAssignable"); | 670 __ Comment("AssertAssignable"); |
| 676 ASSERT(token_pos >= 0); | 671 ASSERT(token_pos >= 0); |
| 677 ASSERT(!dst_type.IsNull()); | 672 ASSERT(!dst_type.IsNull()); |
| 678 ASSERT(dst_type.IsFinalized()); | 673 ASSERT(dst_type.IsFinalized()); |
| 679 // Assignable check is skipped in FlowGraphBuilder, not here. | 674 // Assignable check is skipped in FlowGraphBuilder, not here. |
| 680 ASSERT(dst_type.IsMalformedOrMalbounded() || | 675 ASSERT(dst_type.IsMalformedOrMalbounded() || |
| 681 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 676 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| 682 // Preserve instantiator and its type arguments. | 677 // Preserve instantiator type arguments. |
| 683 __ addiu(SP, SP, Immediate(-2 * kWordSize)); | 678 __ addiu(SP, SP, Immediate(-1 * kWordSize)); |
| 684 __ sw(A2, Address(SP, 1 * kWordSize)); | 679 __ sw(A1, Address(SP, 0 * kWordSize)); |
| 685 | 680 |
| 686 // A null object is always assignable and is returned as result. | 681 // A null object is always assignable and is returned as result. |
| 687 Label is_assignable, runtime_call; | 682 Label is_assignable, runtime_call; |
| 688 | 683 |
| 689 __ BranchEqual(A0, Object::null_object(), &is_assignable); | 684 __ BranchEqual(A0, Object::null_object(), &is_assignable); |
| 690 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); | 685 __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize)); |
| 691 | 686 |
| 692 // Generate throw new TypeError() if the type is malformed or malbounded. | 687 // Generate throw new TypeError() if the type is malformed or malbounded. |
| 693 if (dst_type.IsMalformedOrMalbounded()) { | 688 if (dst_type.IsMalformedOrMalbounded()) { |
| 694 __ addiu(SP, SP, Immediate(-4 * kWordSize)); | 689 __ addiu(SP, SP, Immediate(-4 * kWordSize)); |
| 695 __ LoadObject(TMP, Object::null_object()); | 690 __ LoadObject(TMP, Object::null_object()); |
| 696 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. | 691 __ sw(TMP, Address(SP, 3 * kWordSize)); // Make room for the result. |
| 697 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. | 692 __ sw(A0, Address(SP, 2 * kWordSize)); // Push the source object. |
| 698 __ LoadObject(TMP, dst_name); | 693 __ LoadObject(TMP, dst_name); |
| 699 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. | 694 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the destination name. |
| 700 __ LoadObject(TMP, dst_type); | 695 __ LoadObject(TMP, dst_type); |
| 701 __ sw(TMP, Address(SP, 0 * kWordSize)); // Push the destination type. | 696 __ sw(TMP, Address(SP, 0 * kWordSize)); // Push the destination type. |
| 702 | 697 |
| 703 GenerateRuntimeCall(token_pos, | 698 GenerateRuntimeCall(token_pos, |
| 704 deopt_id, | 699 deopt_id, |
| 705 kBadTypeErrorRuntimeEntry, | 700 kBadTypeErrorRuntimeEntry, |
| 706 3, | 701 3, |
| 707 locs); | 702 locs); |
| 708 // We should never return here. | 703 // We should never return here. |
| 709 __ break_(0); | 704 __ break_(0); |
| 710 | 705 |
| 711 __ Bind(&is_assignable); // For a null object. | 706 __ Bind(&is_assignable); // For a null object. |
| 712 // Restore instantiator and its type arguments. | 707 // Restore instantiator type arguments. |
| 713 __ lw(A1, Address(SP, 0 * kWordSize)); | 708 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 714 __ lw(A2, Address(SP, 1 * kWordSize)); | 709 __ addiu(SP, SP, Immediate(1 * kWordSize)); |
| 715 __ addiu(SP, SP, Immediate(2 * kWordSize)); | |
| 716 return; | 710 return; |
| 717 } | 711 } |
| 718 | 712 |
| 719 // Generate inline type check, linking to runtime call if not assignable. | 713 // Generate inline type check, linking to runtime call if not assignable. |
| 720 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 714 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
| 721 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 715 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
| 722 &is_assignable, &runtime_call); | 716 &is_assignable, &runtime_call); |
| 723 | 717 |
| 724 __ Bind(&runtime_call); | 718 __ Bind(&runtime_call); |
| 725 // Load instantiator (A2) and its type arguments (A1). | 719 // Load instantiator type arguments (A1). |
| 726 __ lw(A1, Address(SP, 0 * kWordSize)); | 720 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 727 __ lw(A2, Address(SP, 1 * kWordSize)); | |
| 728 | 721 |
| 729 __ addiu(SP, SP, Immediate(-7 * kWordSize)); | 722 __ addiu(SP, SP, Immediate(-6 * kWordSize)); |
| 730 __ LoadObject(TMP, Object::null_object()); | 723 __ LoadObject(TMP, Object::null_object()); |
| 731 __ sw(TMP, Address(SP, 6 * kWordSize)); // Make room for the result. | 724 __ sw(TMP, Address(SP, 5 * kWordSize)); // Make room for the result. |
| 732 __ sw(A0, Address(SP, 5 * kWordSize)); // Push the source object. | 725 __ sw(A0, Address(SP, 4 * kWordSize)); // Push the source object. |
| 733 __ LoadObject(TMP, dst_type); | 726 __ LoadObject(TMP, dst_type); |
| 734 __ sw(TMP, Address(SP, 4 * kWordSize)); // Push the type of the destination. | 727 __ sw(TMP, Address(SP, 3 * kWordSize)); // Push the type of the destination. |
| 735 __ sw(A2, Address(SP, 3 * kWordSize)); // Push instantiator. | |
| 736 __ sw(A1, Address(SP, 2 * kWordSize)); // Push type arguments. | 728 __ sw(A1, Address(SP, 2 * kWordSize)); // Push type arguments. |
| 737 __ LoadObject(TMP, dst_name); | 729 __ LoadObject(TMP, dst_name); |
| 738 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination. | 730 __ sw(TMP, Address(SP, 1 * kWordSize)); // Push the name of the destination. |
| 739 __ LoadUniqueObject(T0, test_cache); | 731 __ LoadUniqueObject(T0, test_cache); |
| 740 __ sw(T0, Address(SP, 0 * kWordSize)); | 732 __ sw(T0, Address(SP, 0 * kWordSize)); |
| 741 | 733 |
| 742 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 734 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
| 743 // Pop the parameters supplied to the runtime entry. The result of the | 735 // Pop the parameters supplied to the runtime entry. The result of the |
| 744 // type check runtime call is the checked value. | 736 // type check runtime call is the checked value. |
| 745 __ lw(A0, Address(SP, 6 * kWordSize)); | 737 __ lw(A0, Address(SP, 5 * kWordSize)); |
| 746 __ addiu(SP, SP, Immediate(7 * kWordSize)); | 738 __ addiu(SP, SP, Immediate(6 * kWordSize)); |
| 747 | 739 |
| 748 __ Bind(&is_assignable); | 740 __ Bind(&is_assignable); |
| 749 // Restore instantiator and its type arguments. | 741 // Restore instantiator type arguments. |
| 750 __ lw(A1, Address(SP, 0 * kWordSize)); | 742 __ lw(A1, Address(SP, 0 * kWordSize)); |
| 751 __ lw(A2, Address(SP, 1 * kWordSize)); | 743 __ addiu(SP, SP, Immediate(1 * kWordSize)); |
| 752 __ addiu(SP, SP, Immediate(2 * kWordSize)); | |
| 753 } | 744 } |
| 754 | 745 |
| 755 | 746 |
| 756 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 747 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
| 757 if (is_optimizing()) return; | 748 if (is_optimizing()) return; |
| 758 Definition* defn = instr->AsDefinition(); | 749 Definition* defn = instr->AsDefinition(); |
| 759 if ((defn != NULL) && defn->HasTemp()) { | 750 if ((defn != NULL) && defn->HasTemp()) { |
| 760 __ Push(defn->locs()->out(0).reg()); | 751 __ Push(defn->locs()->out(0).reg()); |
| 761 } | 752 } |
| 762 } | 753 } |
| (...skipping 1142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1905 __ AddImmediate(SP, kDoubleSize); | 1896 __ AddImmediate(SP, kDoubleSize); |
| 1906 } | 1897 } |
| 1907 | 1898 |
| 1908 | 1899 |
| 1909 #undef __ | 1900 #undef __ |
| 1910 | 1901 |
| 1911 | 1902 |
| 1912 } // namespace dart | 1903 } // namespace dart |
| 1913 | 1904 |
| 1914 #endif // defined TARGET_ARCH_MIPS | 1905 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |