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 |