OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
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 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( | 447 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
448 intptr_t token_pos, | 448 intptr_t token_pos, |
449 const AbstractType& type, | 449 const AbstractType& type, |
450 Label* is_instance_lbl, | 450 Label* is_instance_lbl, |
451 Label* is_not_instance_lbl) { | 451 Label* is_not_instance_lbl) { |
452 __ Comment("UninstantiatedTypeTest"); | 452 __ Comment("UninstantiatedTypeTest"); |
453 ASSERT(!type.IsInstantiated()); | 453 ASSERT(!type.IsInstantiated()); |
454 // Skip check if destination is a dynamic type. | 454 // Skip check if destination is a dynamic type. |
455 if (type.IsTypeParameter()) { | 455 if (type.IsTypeParameter()) { |
456 const TypeParameter& type_param = TypeParameter::Cast(type); | 456 const TypeParameter& type_param = TypeParameter::Cast(type); |
457 // Load instantiator (or null) and instantiator type arguments on stack. | 457 // Load instantiator type arguments on stack. |
458 __ ldr(R1, Address(SP)); // Get instantiator type arguments. | 458 __ ldr(R1, Address(SP)); // Get instantiator type arguments. |
459 // R1: instantiator type arguments. | 459 // R1: instantiator type arguments. |
460 // Check if type arguments are null, i.e. equivalent to vector of dynamic. | 460 // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
461 __ CompareObject(R1, Object::null_object()); | 461 __ CompareObject(R1, Object::null_object()); |
462 __ b(is_instance_lbl, EQ); | 462 __ b(is_instance_lbl, EQ); |
463 __ LoadFieldFromOffset( | 463 __ LoadFieldFromOffset( |
464 R2, R1, TypeArguments::type_at_offset(type_param.index())); | 464 R2, R1, TypeArguments::type_at_offset(type_param.index())); |
465 // R2: concrete type of type. | 465 // R2: concrete type of type. |
466 // Check if type argument is dynamic. | 466 // Check if type argument is dynamic. |
467 __ CompareObject(R2, Object::dynamic_type()); | 467 __ CompareObject(R2, Object::dynamic_type()); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 | 572 |
573 | 573 |
574 // If instanceof type test cannot be performed successfully at compile time and | 574 // If instanceof type test cannot be performed successfully at compile time and |
575 // therefore eliminated, optimize it by adding inlined tests for: | 575 // therefore eliminated, optimize it by adding inlined tests for: |
576 // - NULL -> return false. | 576 // - NULL -> return false. |
577 // - Smi -> compile time subtype check (only if dst class is not parameterized). | 577 // - Smi -> compile time subtype check (only if dst class is not parameterized). |
578 // - Class equality (only if class is not parameterized). | 578 // - Class equality (only if class is not parameterized). |
579 // Inputs: | 579 // Inputs: |
580 // - R0: object. | 580 // - R0: object. |
581 // - R1: instantiator type arguments or raw_null. | 581 // - R1: instantiator type arguments or raw_null. |
582 // - R2: instantiator or raw_null. | |
583 // Returns: | 582 // Returns: |
584 // - true or false in R0. | 583 // - true or false in R0. |
585 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, | 584 void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos, |
586 intptr_t deopt_id, | 585 intptr_t deopt_id, |
587 const AbstractType& type, | 586 const AbstractType& type, |
588 bool negate_result, | 587 bool negate_result, |
589 LocationSummary* locs) { | 588 LocationSummary* locs) { |
590 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); | 589 ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded()); |
591 | 590 |
592 // Preserve instantiator (R2) and its type arguments (R1). | 591 // Preserve instantiator type arguments (R1). |
593 __ Push(R2); | |
594 __ Push(R1); | 592 __ Push(R1); |
595 | 593 |
596 Label is_instance, is_not_instance; | 594 Label is_instance, is_not_instance; |
597 // If type is instantiated and non-parameterized, we can inline code | 595 // If type is instantiated and non-parameterized, we can inline code |
598 // checking whether the tested instance is a Smi. | 596 // checking whether the tested instance is a Smi. |
599 if (type.IsInstantiated()) { | 597 if (type.IsInstantiated()) { |
600 // A null object is only an instance of Object and dynamic, which has | 598 // A null object is only an instance of Object and dynamic, which has |
601 // already been checked above (if the type is instantiated). So we can | 599 // already been checked above (if the type is instantiated). So we can |
602 // return false here if the instance is null (and if the type is | 600 // return false here if the instance is null (and if the type is |
603 // instantiated). | 601 // instantiated). |
604 // We can only inline this null check if the type is instantiated at compile | 602 // We can only inline this null check if the type is instantiated at compile |
605 // time, since an uninstantiated type at compile time could be Object or | 603 // time, since an uninstantiated type at compile time could be Object or |
606 // dynamic at run time. | 604 // dynamic at run time. |
607 __ CompareObject(R0, Object::null_object()); | 605 __ CompareObject(R0, Object::null_object()); |
608 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); | 606 __ b(type.IsNullType() ? &is_instance : &is_not_instance, EQ); |
609 } | 607 } |
610 | 608 |
611 // Generate inline instanceof test. | 609 // Generate inline instanceof test. |
612 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 610 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
613 test_cache = GenerateInlineInstanceof(token_pos, type, | 611 test_cache = GenerateInlineInstanceof(token_pos, type, |
614 &is_instance, &is_not_instance); | 612 &is_instance, &is_not_instance); |
615 | 613 |
616 // test_cache is null if there is no fall-through. | 614 // test_cache is null if there is no fall-through. |
617 Label done; | 615 Label done; |
618 if (!test_cache.IsNull()) { | 616 if (!test_cache.IsNull()) { |
619 // Generate runtime call. | 617 // Generate runtime call. |
620 // Load instantiator (R2) and its type arguments (R1). | 618 // Load instantiator (R2) and its type arguments (R1). |
621 __ ldr(R1, Address(SP, 0 * kWordSize)); | 619 __ ldr(R1, Address(SP, 0 * kWordSize)); |
622 __ ldr(R2, Address(SP, 1 * kWordSize)); | |
623 __ PushObject(Object::null_object()); // Make room for the result. | 620 __ PushObject(Object::null_object()); // Make room for the result. |
624 __ Push(R0); // Push the instance. | 621 __ Push(R0); // Push the instance. |
625 __ PushObject(type); // Push the type. | 622 __ PushObject(type); // Push the type. |
626 // Push instantiator (R2) and its type arguments (R1). | 623 __ Push(R1); // Push instantiator type arguments (R1). |
627 __ Push(R2); | |
628 __ Push(R1); | |
629 __ LoadUniqueObject(R0, test_cache); | 624 __ LoadUniqueObject(R0, test_cache); |
630 __ Push(R0); | 625 __ Push(R0); |
631 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); | 626 GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
632 // Pop the parameters supplied to the runtime entry. The result of the | 627 // 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. | 628 // instanceof runtime call will be left as the result of the operation. |
634 __ Drop(5); | 629 __ Drop(4); |
635 if (negate_result) { | 630 if (negate_result) { |
636 __ Pop(R1); | 631 __ Pop(R1); |
637 __ LoadObject(R0, Bool::True()); | 632 __ LoadObject(R0, Bool::True()); |
638 __ CompareRegisters(R1, R0); | 633 __ CompareRegisters(R1, R0); |
639 __ b(&done, NE); | 634 __ b(&done, NE); |
640 __ LoadObject(R0, Bool::False()); | 635 __ LoadObject(R0, Bool::False()); |
641 } else { | 636 } else { |
642 __ Pop(R0); | 637 __ Pop(R0); |
643 } | 638 } |
644 __ b(&done); | 639 __ b(&done); |
645 } | 640 } |
646 __ Bind(&is_not_instance); | 641 __ Bind(&is_not_instance); |
647 __ LoadObject(R0, Bool::Get(negate_result)); | 642 __ LoadObject(R0, Bool::Get(negate_result)); |
648 __ b(&done); | 643 __ b(&done); |
649 | 644 |
650 __ Bind(&is_instance); | 645 __ Bind(&is_instance); |
651 __ LoadObject(R0, Bool::Get(!negate_result)); | 646 __ LoadObject(R0, Bool::Get(!negate_result)); |
652 __ Bind(&done); | 647 __ Bind(&done); |
653 // Remove instantiator (R2) and its type arguments (R1). | 648 // Remove instantiator type arguments (R1). |
654 __ Drop(2); | 649 __ Drop(1); |
655 } | 650 } |
656 | 651 |
657 | 652 |
658 // Optimize assignable type check by adding inlined tests for: | 653 // Optimize assignable type check by adding inlined tests for: |
659 // - NULL -> return NULL. | 654 // - NULL -> return NULL. |
660 // - 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). |
661 // - Class equality (only if class is not parameterized). | 656 // - Class equality (only if class is not parameterized). |
662 // Inputs: | 657 // Inputs: |
663 // - R0: instance being type checked. | 658 // - R0: instance being type checked. |
664 // - R1: instantiator type arguments or raw_null. | 659 // - R1: instantiator type arguments or raw_null. |
665 // - R2: instantiator or raw_null. | |
666 // Returns: | 660 // Returns: |
667 // - object in R0 for successful assignable check (or throws TypeError). | 661 // - object in R0 for successful assignable check (or throws TypeError). |
668 // Performance notes: positive checks must be quick, negative checks can be slow | 662 // Performance notes: positive checks must be quick, negative checks can be slow |
669 // as they throw an exception. | 663 // as they throw an exception. |
670 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 664 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
671 intptr_t deopt_id, | 665 intptr_t deopt_id, |
672 const AbstractType& dst_type, | 666 const AbstractType& dst_type, |
673 const String& dst_name, | 667 const String& dst_name, |
674 LocationSummary* locs) { | 668 LocationSummary* locs) { |
675 ASSERT(token_pos >= 0); | 669 ASSERT(token_pos >= 0); |
676 ASSERT(!dst_type.IsNull()); | 670 ASSERT(!dst_type.IsNull()); |
677 ASSERT(dst_type.IsFinalized()); | 671 ASSERT(dst_type.IsFinalized()); |
678 // Assignable check is skipped in FlowGraphBuilder, not here. | 672 // Assignable check is skipped in FlowGraphBuilder, not here. |
679 ASSERT(dst_type.IsMalformedOrMalbounded() || | 673 ASSERT(dst_type.IsMalformedOrMalbounded() || |
680 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); | 674 (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
681 // Preserve instantiator (R2) and its type arguments (R1). | 675 // Preserve instantiator type arguments (R1). |
682 __ Push(R2); | |
683 __ Push(R1); | 676 __ Push(R1); |
684 // A null object is always assignable and is returned as result. | 677 // A null object is always assignable and is returned as result. |
685 Label is_assignable, runtime_call; | 678 Label is_assignable, runtime_call; |
686 __ CompareObject(R0, Object::null_object()); | 679 __ CompareObject(R0, Object::null_object()); |
687 __ b(&is_assignable, EQ); | 680 __ b(&is_assignable, EQ); |
688 | 681 |
689 // Generate throw new TypeError() if the type is malformed or malbounded. | 682 // Generate throw new TypeError() if the type is malformed or malbounded. |
690 if (dst_type.IsMalformedOrMalbounded()) { | 683 if (dst_type.IsMalformedOrMalbounded()) { |
691 __ PushObject(Object::null_object()); // Make room for the result. | 684 __ PushObject(Object::null_object()); // Make room for the result. |
692 __ Push(R0); // Push the source object. | 685 __ Push(R0); // Push the source object. |
693 __ PushObject(dst_name); // Push the name of the destination. | 686 __ PushObject(dst_name); // Push the name of the destination. |
694 __ PushObject(dst_type); // Push the type of the destination. | 687 __ PushObject(dst_type); // Push the type of the destination. |
695 GenerateRuntimeCall(token_pos, | 688 GenerateRuntimeCall(token_pos, |
696 deopt_id, | 689 deopt_id, |
697 kBadTypeErrorRuntimeEntry, | 690 kBadTypeErrorRuntimeEntry, |
698 3, | 691 3, |
699 locs); | 692 locs); |
700 // We should never return here. | 693 // We should never return here. |
701 __ brk(0); | 694 __ brk(0); |
702 | 695 |
703 __ Bind(&is_assignable); // For a null object. | 696 __ Bind(&is_assignable); // For a null object. |
704 // Restore instantiator (R2) and its type arguments (R1). | 697 // Restore instantiator type arguments (R1). |
705 __ Pop(R1); | 698 __ Pop(R1); |
706 __ Pop(R2); | |
707 return; | 699 return; |
708 } | 700 } |
709 | 701 |
710 // Generate inline type check, linking to runtime call if not assignable. | 702 // Generate inline type check, linking to runtime call if not assignable. |
711 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); | 703 SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle(zone()); |
712 test_cache = GenerateInlineInstanceof(token_pos, dst_type, | 704 test_cache = GenerateInlineInstanceof(token_pos, dst_type, |
713 &is_assignable, &runtime_call); | 705 &is_assignable, &runtime_call); |
714 | 706 |
715 __ Bind(&runtime_call); | 707 __ Bind(&runtime_call); |
716 // Load instantiator (R2) and its type arguments (R1). | 708 __ ldr(R1, Address(SP)); // Load instantiator type arguments (R1). |
717 __ ldr(R1, Address(SP)); | |
718 __ ldr(R2, Address(SP, 1 * kWordSize)); | |
719 __ PushObject(Object::null_object()); // Make room for the result. | 709 __ PushObject(Object::null_object()); // Make room for the result. |
720 __ Push(R0); // Push the source object. | 710 __ Push(R0); // Push the source object. |
721 __ PushObject(dst_type); // Push the type of the destination. | 711 __ PushObject(dst_type); // Push the type of the destination. |
722 // Push instantiator (R2) and its type arguments (R1). | 712 __ Push(R1); // Push instantiator type arguments (R1). |
723 __ Push(R2); | |
724 __ Push(R1); | |
725 __ PushObject(dst_name); // Push the name of the destination. | 713 __ PushObject(dst_name); // Push the name of the destination. |
726 __ LoadUniqueObject(R0, test_cache); | 714 __ LoadUniqueObject(R0, test_cache); |
727 __ Push(R0); | 715 __ Push(R0); |
728 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); | 716 GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
729 // Pop the parameters supplied to the runtime entry. The result of the | 717 // Pop the parameters supplied to the runtime entry. The result of the |
730 // type check runtime call is the checked value. | 718 // type check runtime call is the checked value. |
731 __ Drop(6); | 719 __ Drop(5); |
732 __ Pop(R0); | 720 __ Pop(R0); |
733 | 721 |
734 __ Bind(&is_assignable); | 722 __ Bind(&is_assignable); |
735 // Restore instantiator (R2) and its type arguments (R1). | 723 // Restore instantiator type arguments (R1). |
736 __ Pop(R1); | 724 __ Pop(R1); |
737 __ Pop(R2); | |
738 } | 725 } |
739 | 726 |
740 | 727 |
741 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 728 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
742 if (is_optimizing()) { | 729 if (is_optimizing()) { |
743 return; | 730 return; |
744 } | 731 } |
745 Definition* defn = instr->AsDefinition(); | 732 Definition* defn = instr->AsDefinition(); |
746 if ((defn != NULL) && defn->HasTemp()) { | 733 if ((defn != NULL) && defn->HasTemp()) { |
747 __ Push(defn->locs()->out(0).reg()); | 734 __ Push(defn->locs()->out(0).reg()); |
(...skipping 1135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1883 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 1870 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
1884 __ PopDouble(reg); | 1871 __ PopDouble(reg); |
1885 } | 1872 } |
1886 | 1873 |
1887 | 1874 |
1888 #undef __ | 1875 #undef __ |
1889 | 1876 |
1890 } // namespace dart | 1877 } // namespace dart |
1891 | 1878 |
1892 #endif // defined TARGET_ARCH_ARM64 | 1879 #endif // defined TARGET_ARCH_ARM64 |
OLD | NEW |