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