Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/intermediate_language.h" | 5 #include "vm/intermediate_language.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/flow_graph_builder.h" | 8 #include "vm/flow_graph_builder.h" |
| 9 #include "vm/flow_graph_compiler.h" | |
| 10 #include "vm/locations.h" | |
| 9 #include "vm/object.h" | 11 #include "vm/object.h" |
| 10 #include "vm/os.h" | 12 #include "vm/os.h" |
| 11 #include "vm/scopes.h" | 13 #include "vm/scopes.h" |
| 14 #include "vm/stub_code.h" | |
| 12 | 15 |
| 13 namespace dart { | 16 namespace dart { |
| 14 | 17 |
| 15 // ==== Support for visiting flow graphs. | 18 // ==== Support for visiting flow graphs. |
| 16 #define DEFINE_ACCEPT(ShortName, ClassName) \ | 19 #define DEFINE_ACCEPT(ShortName, ClassName) \ |
| 17 void ClassName::Accept(FlowGraphVisitor* visitor) { \ | 20 void ClassName::Accept(FlowGraphVisitor* visitor) { \ |
| 18 visitor->Visit##ShortName(this); \ | 21 visitor->Visit##ShortName(this); \ |
| 19 } | 22 } |
| 20 | 23 |
| 21 FOR_EACH_COMPUTATION(DEFINE_ACCEPT) | 24 FOR_EACH_COMPUTATION(DEFINE_ACCEPT) |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 RawAbstractType* UnarySmiOpComp::StaticType() const { | 582 RawAbstractType* UnarySmiOpComp::StaticType() const { |
| 580 return Type::IntInterface(); | 583 return Type::IntInterface(); |
| 581 } | 584 } |
| 582 | 585 |
| 583 | 586 |
| 584 RawAbstractType* NumberNegateComp::StaticType() const { | 587 RawAbstractType* NumberNegateComp::StaticType() const { |
| 585 return Type::NumberInterface(); | 588 return Type::NumberInterface(); |
| 586 } | 589 } |
| 587 | 590 |
| 588 | 591 |
| 592 // Shared code generation methods (EmitNativeCode, MakeLocationSummary, and | |
| 593 // PrepareEntry). Only assembly code that can be shared across all architectures | |
| 594 // can be used. Machine specific register allocation and code generation | |
| 595 // is located in intermediate_language_<arch>.cc | |
| 596 | |
| 597 | |
| 598 // True iff. the arguments to a call will be properly pushed and can | |
| 599 // be popped after the call. | |
| 600 template <typename T> static bool VerifyCallComputation(T* comp) { | |
| 601 // Argument values should be consecutive temps. | |
| 602 // | |
| 603 // TODO(kmillikin): implement stack height tracking so we can also assert | |
| 604 // they are on top of the stack. | |
| 605 intptr_t previous = -1; | |
| 606 for (int i = 0; i < comp->ArgumentCount(); ++i) { | |
| 607 Value* val = comp->ArgumentAt(i); | |
| 608 if (!val->IsUse()) return false; | |
| 609 intptr_t current = val->AsUse()->definition()->temp_index(); | |
| 610 if (i != 0) { | |
| 611 if (current != (previous + 1)) return false; | |
| 612 } | |
| 613 previous = current; | |
| 614 } | |
| 615 return true; | |
| 616 } | |
| 617 | |
| 618 | |
| 619 // Truee iff. the v2 is above v1 on stack, or one of them is constant. | |
| 620 static bool VerifyValues(Value* v1, Value* v2) { | |
| 621 ASSERT(v1->IsUse() && v2->IsUse()); | |
| 622 return (v1->AsUse()->definition()->temp_index() + 1) == | |
| 623 v2->AsUse()->definition()->temp_index(); | |
| 624 } | |
| 625 | |
| 626 | |
| 627 #define __ compiler->assembler()-> | |
| 628 | |
| 629 void GraphEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { | |
| 630 // Nothing to do. | |
| 631 } | |
| 632 | |
| 633 | |
| 634 void JoinEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { | |
| 635 __ Bind(compiler->GetBlockLabel(this)); | |
| 636 } | |
| 637 | |
| 638 | |
| 639 void TargetEntryInstr::PrepareEntry(FlowGraphCompiler* compiler) { | |
| 640 __ Bind(compiler->GetBlockLabel(this)); | |
| 641 if (HasTryIndex()) { | |
| 642 compiler->AddExceptionHandler(try_index(), | |
| 643 compiler->assembler()->CodeSize()); | |
| 644 } | |
| 645 } | |
| 646 | |
| 647 | |
| 648 LocationSummary* ThrowInstr::MakeLocationSummary() const { | |
| 649 const int kNumInputs = 0; | |
| 650 const int kNumTemps = 0; | |
| 651 return new LocationSummary(kNumInputs, kNumTemps); | |
| 652 } | |
| 653 | |
| 654 | |
| 655 | |
| 656 void ThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 657 ASSERT(exception()->IsUse()); | |
| 658 compiler->GenerateCallRuntime(cid(), | |
| 659 token_index(), | |
| 660 try_index(), | |
| 661 kThrowRuntimeEntry); | |
| 662 __ int3(); | |
|
Ivan Posva
2012/06/07 06:54:27
How can this be shared code?
| |
| 663 } | |
| 664 | |
| 665 | |
| 666 LocationSummary* ReThrowInstr::MakeLocationSummary() const { | |
| 667 const int kNumInputs = 0; | |
| 668 const int kNumTemps = 0; | |
| 669 return new LocationSummary(kNumInputs, kNumTemps); | |
| 670 } | |
| 671 | |
| 672 | |
| 673 void ReThrowInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 674 ASSERT(exception()->IsUse()); | |
| 675 ASSERT(stack_trace()->IsUse()); | |
| 676 compiler->GenerateCallRuntime(cid(), | |
| 677 token_index(), | |
| 678 try_index(), | |
| 679 kReThrowRuntimeEntry); | |
| 680 __ int3(); | |
|
Ivan Posva
2012/06/07 06:54:27
ditto!
| |
| 681 } | |
| 682 | |
| 683 | |
| 684 LocationSummary* BranchInstr::MakeLocationSummary() const { | |
| 685 const int kNumInputs = 1; | |
| 686 const int kNumTemps = 0; | |
| 687 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | |
| 688 locs->set_in(0, Location::RequiresRegister()); | |
| 689 return locs; | |
| 690 } | |
| 691 | |
| 692 | |
| 693 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 694 Register value = locs()->in(0).reg(); | |
| 695 __ CompareObject(value, Bool::ZoneHandle(Bool::True())); | |
| 696 if (compiler->IsNextBlock(false_successor())) { | |
| 697 // If the next block is the false successor we will fall through to it if | |
| 698 // comparison with true fails. | |
| 699 __ j(EQUAL, compiler->GetBlockLabel(true_successor())); | |
|
Ivan Posva
2012/06/07 06:54:27
This is definitely not a portable assembler instru
| |
| 700 } else { | |
| 701 ASSERT(compiler->IsNextBlock(true_successor())); | |
| 702 // If the next block is the true successor we negate comparison and fall | |
| 703 // through to it. | |
| 704 __ j(NOT_EQUAL, compiler->GetBlockLabel(false_successor())); | |
| 705 } | |
| 706 } | |
| 707 | |
| 708 | |
| 709 LocationSummary* CurrentContextComp::MakeLocationSummary() const { | |
| 710 return LocationSummary::Make(0, Location::RequiresRegister()); | |
| 711 } | |
| 712 | |
| 713 | |
| 714 void CurrentContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 715 __ MoveRegister(locs()->out().reg(), CTX); | |
|
Ivan Posva
2012/06/07 06:54:27
CTX sounds like a very CPU-specific register to me
| |
| 716 } | |
| 717 | |
| 718 | |
| 719 LocationSummary* StoreContextComp::MakeLocationSummary() const { | |
| 720 const intptr_t kNumInputs = 1; | |
| 721 const intptr_t kNumTemps = 0; | |
| 722 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | |
| 723 summary->set_in(0, Location::RegisterLocation(CTX)); | |
| 724 return summary; | |
| 725 } | |
| 726 | |
| 727 | |
| 728 void StoreContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 729 // Nothing to do. Context register were loaded by register allocator. | |
| 730 ASSERT(locs()->in(0).reg() == CTX); | |
| 731 } | |
| 732 | |
| 733 | |
| 734 LocationSummary* StrictCompareComp::MakeLocationSummary() const { | |
| 735 return LocationSummary::Make(2, Location::SameAsFirstInput()); | |
| 736 } | |
| 737 | |
| 738 | |
| 739 void StrictCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 740 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
| 741 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
| 742 | |
| 743 Register left = locs()->in(0).reg(); | |
| 744 Register right = locs()->in(1).reg(); | |
| 745 Register result = locs()->out().reg(); | |
| 746 | |
| 747 __ CompareRegisters(left, right); | |
| 748 Label load_true, done; | |
| 749 if (kind() == Token::kEQ_STRICT) { | |
| 750 __ j(EQUAL, &load_true, Assembler::kNearJump); | |
| 751 } else { | |
| 752 ASSERT(kind() == Token::kNE_STRICT); | |
| 753 __ j(NOT_EQUAL, &load_true, Assembler::kNearJump); | |
| 754 } | |
| 755 __ LoadObject(result, bool_false); | |
| 756 __ jmp(&done, Assembler::kNearJump); | |
| 757 __ Bind(&load_true); | |
| 758 __ LoadObject(result, bool_true); | |
| 759 __ Bind(&done); | |
| 760 } | |
| 761 | |
| 762 | |
| 763 void ClosureCallComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 764 ASSERT(VerifyCallComputation(this)); | |
| 765 // The arguments to the stub include the closure. The arguments | |
| 766 // descriptor describes the closure's arguments (and so does not include | |
| 767 // the closure). | |
| 768 Register temp_reg = locs()->temp(0).reg(); | |
| 769 int argument_count = ArgumentCount(); | |
| 770 const Array& arguments_descriptor = | |
| 771 CodeGenerator::ArgumentsDescriptor(argument_count - 1, | |
| 772 argument_names()); | |
| 773 __ LoadObject(temp_reg, arguments_descriptor); | |
| 774 | |
| 775 compiler->GenerateCall(token_index(), | |
| 776 try_index(), | |
| 777 &StubCode::CallClosureFunctionLabel(), | |
| 778 PcDescriptors::kOther); | |
| 779 __ Drop(argument_count); | |
| 780 } | |
| 781 | |
| 782 | |
| 783 LocationSummary* InstanceCallComp::MakeLocationSummary() const { | |
| 784 return MakeCallSummary(); | |
| 785 } | |
| 786 | |
| 787 | |
| 788 void InstanceCallComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 789 ASSERT(VerifyCallComputation(this)); | |
| 790 compiler->AddCurrentDescriptor(PcDescriptors::kDeopt, | |
| 791 cid(), | |
| 792 token_index(), | |
| 793 try_index()); | |
| 794 compiler->GenerateInstanceCall(cid(), | |
| 795 token_index(), | |
| 796 try_index(), | |
| 797 function_name(), | |
| 798 ArgumentCount(), | |
| 799 argument_names(), | |
| 800 checked_argument_count()); | |
| 801 } | |
| 802 | |
| 803 | |
| 804 LocationSummary* StaticCallComp::MakeLocationSummary() const { | |
| 805 return MakeCallSummary(); | |
| 806 } | |
| 807 | |
| 808 | |
| 809 void StaticCallComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 810 ASSERT(VerifyCallComputation(this)); | |
| 811 compiler->GenerateStaticCall(cid(), | |
| 812 token_index(), | |
| 813 try_index(), | |
| 814 function(), | |
| 815 ArgumentCount(), | |
| 816 argument_names()); | |
| 817 } | |
| 818 | |
| 819 | |
| 820 LocationSummary* UseVal::MakeLocationSummary() const { | |
| 821 return NULL; | |
| 822 } | |
| 823 | |
| 824 | |
| 825 void UseVal::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 826 UNIMPLEMENTED(); | |
| 827 } | |
| 828 | |
| 829 | |
| 830 void AssertAssignableComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 831 compiler->GenerateAssertAssignable(cid(), | |
| 832 token_index(), | |
| 833 try_index(), | |
| 834 dst_type(), | |
| 835 dst_name()); | |
| 836 ASSERT(locs()->in(0).reg() == locs()->out().reg()); | |
| 837 } | |
| 838 | |
| 839 | |
| 840 LocationSummary* AssertBooleanComp::MakeLocationSummary() const { | |
| 841 return LocationSummary::Make(1, Location::SameAsFirstInput()); | |
| 842 } | |
| 843 | |
| 844 | |
| 845 LocationSummary* StoreInstanceFieldComp::MakeLocationSummary() const { | |
| 846 return LocationSummary::Make(2, Location::RequiresRegister()); | |
| 847 } | |
| 848 | |
| 849 | |
| 850 void StoreInstanceFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 851 ASSERT(VerifyValues(instance(), value())); | |
| 852 Register instance = locs()->in(0).reg(); | |
| 853 Register value = locs()->in(1).reg(); | |
| 854 Register result = locs()->out().reg(); | |
| 855 | |
| 856 __ StoreIntoObject(instance, FieldAddress(instance, field().Offset()), | |
| 857 value); | |
| 858 // TODO(fschneider): Consider eliminating this move by specifying a | |
| 859 // SameAsSecondInput for the result. | |
| 860 __ MoveRegister(result, value); | |
| 861 } | |
| 862 | |
| 863 | |
| 864 LocationSummary* StoreStaticFieldComp::MakeLocationSummary() const { | |
| 865 LocationSummary* locs = new LocationSummary(1, 1); | |
| 866 locs->set_in(0, Location::RequiresRegister()); | |
| 867 locs->set_temp(0, Location::RequiresRegister()); | |
| 868 locs->set_out(Location::SameAsFirstInput()); | |
| 869 return locs; | |
| 870 } | |
| 871 | |
| 872 | |
| 873 void StoreStaticFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 874 Register value = locs()->in(0).reg(); | |
| 875 Register temp = locs()->temp(0).reg(); | |
| 876 ASSERT(locs()->out().reg() == value); | |
| 877 | |
| 878 __ LoadObject(temp, field()); | |
| 879 __ StoreIntoObject(temp, FieldAddress(temp, Field::value_offset()), value); | |
| 880 } | |
| 881 | |
| 882 | |
| 883 LocationSummary* BooleanNegateComp::MakeLocationSummary() const { | |
| 884 return LocationSummary::Make(1, Location::RequiresRegister()); | |
| 885 } | |
| 886 | |
| 887 | |
| 888 void BooleanNegateComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 889 Register value = locs()->in(0).reg(); | |
| 890 Register result = locs()->out().reg(); | |
| 891 | |
| 892 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
| 893 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
| 894 Label done; | |
| 895 __ LoadObject(result, bool_true); | |
| 896 __ CompareRegisters(result, value); | |
| 897 __ j(NOT_EQUAL, &done, Assembler::kNearJump); | |
| 898 __ LoadObject(result, bool_false); | |
| 899 __ Bind(&done); | |
| 900 } | |
| 901 | |
| 902 | |
| 903 LocationSummary* ChainContextComp::MakeLocationSummary() const { | |
| 904 return LocationSummary::Make(1, Location::NoLocation()); | |
| 905 } | |
| 906 | |
| 907 | |
| 908 void ChainContextComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 909 Register context_value = locs()->in(0).reg(); | |
| 910 | |
| 911 // Chain the new context in context_value to its parent in CTX. | |
| 912 __ StoreIntoObject(context_value, | |
| 913 FieldAddress(context_value, Context::parent_offset()), | |
| 914 CTX); | |
| 915 // Set new context as current context. | |
| 916 __ MoveRegister(CTX, context_value); | |
| 917 } | |
| 918 | |
| 919 | |
| 920 LocationSummary* StoreVMFieldComp::MakeLocationSummary() const { | |
| 921 return LocationSummary::Make(2, Location::SameAsFirstInput()); | |
| 922 } | |
| 923 | |
| 924 | |
| 925 void StoreVMFieldComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 926 Register value_reg = locs()->in(0).reg(); | |
| 927 Register dest_reg = locs()->in(1).reg(); | |
| 928 ASSERT(value_reg == locs()->out().reg()); | |
| 929 | |
| 930 __ StoreIntoObject(dest_reg, FieldAddress(dest_reg, offset_in_bytes()), | |
| 931 value_reg); | |
| 932 } | |
| 933 | |
| 934 | |
| 935 LocationSummary* AllocateObjectComp::MakeLocationSummary() const { | |
| 936 return MakeCallSummary(); | |
| 937 } | |
| 938 | |
| 939 | |
| 940 void AllocateObjectComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 941 const Class& cls = Class::ZoneHandle(constructor().owner()); | |
| 942 const Code& stub = Code::Handle(StubCode::GetAllocationStubForClass(cls)); | |
| 943 const ExternalLabel label(cls.ToCString(), stub.EntryPoint()); | |
| 944 compiler->GenerateCall(token_index(), | |
| 945 try_index(), | |
| 946 &label, | |
| 947 PcDescriptors::kOther); | |
| 948 __ Drop(arguments().length()); // Discard arguments. | |
| 949 } | |
| 950 | |
| 951 | |
| 952 LocationSummary* CreateClosureComp::MakeLocationSummary() const { | |
| 953 return MakeCallSummary(); | |
| 954 } | |
| 955 | |
| 956 | |
| 957 void CreateClosureComp::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 958 const Function& closure_function = function(); | |
| 959 const Code& stub = Code::Handle( | |
| 960 StubCode::GetAllocationStubForClosure(closure_function)); | |
| 961 const ExternalLabel label(closure_function.ToCString(), stub.EntryPoint()); | |
| 962 compiler->GenerateCall(token_index(), try_index(), &label, | |
| 963 PcDescriptors::kOther); | |
| 964 __ Drop(2); // Discard type arguments and receiver. | |
| 965 } | |
| 966 | |
| 967 #undef __ | |
| 589 | 968 |
| 590 } // namespace dart | 969 } // namespace dart |
| OLD | NEW |