OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/interpreter/bytecode-array-builder.h" | 5 #include "src/interpreter/bytecode-array-builder.h" |
6 | 6 |
7 namespace v8 { | 7 namespace v8 { |
8 namespace internal { | 8 namespace internal { |
9 namespace interpreter { | 9 namespace interpreter { |
10 | 10 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 array_builder_.bytecodes()->at(operand_offset)); | 45 array_builder_.bytecodes()->at(operand_offset)); |
46 case OperandSize::kShort: | 46 case OperandSize::kShort: |
47 uint16_t operand = | 47 uint16_t operand = |
48 (array_builder_.bytecodes()->at(operand_offset) << 8) + | 48 (array_builder_.bytecodes()->at(operand_offset) << 8) + |
49 array_builder_.bytecodes()->at(operand_offset + 1); | 49 array_builder_.bytecodes()->at(operand_offset + 1); |
50 return static_cast<uint32_t>(operand); | 50 return static_cast<uint32_t>(operand); |
51 } | 51 } |
52 } | 52 } |
53 | 53 |
54 Handle<Object> GetConstantForIndexOperand(int operand_index) const { | 54 Handle<Object> GetConstantForIndexOperand(int operand_index) const { |
55 return array_builder_.constants_.at(GetOperand(operand_index)); | 55 return array_builder_.constant_array_builder()->At( |
| 56 GetOperand(operand_index)); |
56 } | 57 } |
57 | 58 |
58 private: | 59 private: |
59 const BytecodeArrayBuilder& array_builder_; | 60 const BytecodeArrayBuilder& array_builder_; |
60 size_t previous_bytecode_start_; | 61 size_t previous_bytecode_start_; |
61 | 62 |
62 DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper); | 63 DISALLOW_COPY_AND_ASSIGN(PreviousBytecodeHelper); |
63 }; | 64 }; |
64 | 65 |
65 | 66 |
66 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) | 67 BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone) |
67 : isolate_(isolate), | 68 : isolate_(isolate), |
68 zone_(zone), | 69 zone_(zone), |
69 bytecodes_(zone), | 70 bytecodes_(zone), |
70 bytecode_generated_(false), | 71 bytecode_generated_(false), |
| 72 constant_array_builder_(isolate, zone), |
71 last_block_end_(0), | 73 last_block_end_(0), |
72 last_bytecode_start_(~0), | 74 last_bytecode_start_(~0), |
73 exit_seen_in_block_(false), | 75 exit_seen_in_block_(false), |
74 unbound_jumps_(0), | 76 unbound_jumps_(0), |
75 constants_map_(isolate->heap(), zone), | |
76 constants_(zone), | |
77 parameter_count_(-1), | 77 parameter_count_(-1), |
78 local_register_count_(-1), | 78 local_register_count_(-1), |
79 context_register_count_(-1), | 79 context_register_count_(-1), |
80 temporary_register_count_(0), | 80 temporary_register_count_(0), |
81 free_temporaries_(zone) {} | 81 free_temporaries_(zone) {} |
82 | 82 |
83 | 83 |
84 BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); } | 84 BytecodeArrayBuilder::~BytecodeArrayBuilder() { DCHECK_EQ(0, unbound_jumps_); } |
85 | 85 |
86 | 86 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 | 137 |
138 | 138 |
139 bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const { | 139 bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const { |
140 return temporary_register_count_ > 0 && first_temporary_register() <= reg && | 140 return temporary_register_count_ > 0 && first_temporary_register() <= reg && |
141 reg <= last_temporary_register(); | 141 reg <= last_temporary_register(); |
142 } | 142 } |
143 | 143 |
144 | 144 |
145 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { | 145 Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() { |
146 DCHECK_EQ(bytecode_generated_, false); | 146 DCHECK_EQ(bytecode_generated_, false); |
147 | |
148 EnsureReturn(); | 147 EnsureReturn(); |
149 | 148 |
150 int bytecode_size = static_cast<int>(bytecodes_.size()); | 149 int bytecode_size = static_cast<int>(bytecodes_.size()); |
151 int register_count = fixed_register_count() + temporary_register_count_; | 150 int register_count = fixed_register_count() + temporary_register_count_; |
152 int frame_size = register_count * kPointerSize; | 151 int frame_size = register_count * kPointerSize; |
153 | |
154 Factory* factory = isolate_->factory(); | 152 Factory* factory = isolate_->factory(); |
155 int constants_count = static_cast<int>(constants_.size()); | |
156 Handle<FixedArray> constant_pool = | 153 Handle<FixedArray> constant_pool = |
157 factory->NewFixedArray(constants_count, TENURED); | 154 constant_array_builder()->ToFixedArray(factory); |
158 for (int i = 0; i < constants_count; i++) { | |
159 constant_pool->set(i, *constants_[i]); | |
160 } | |
161 | |
162 Handle<BytecodeArray> output = | 155 Handle<BytecodeArray> output = |
163 factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, | 156 factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, |
164 parameter_count(), constant_pool); | 157 parameter_count(), constant_pool); |
165 bytecode_generated_ = true; | 158 bytecode_generated_ = true; |
166 return output; | 159 return output; |
167 } | 160 } |
168 | 161 |
169 | 162 |
170 template <size_t N> | 163 template <size_t N> |
171 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) { | 164 void BytecodeArrayBuilder::Output(Bytecode bytecode, uint32_t(&operands)[N]) { |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 case Bytecode::kJumpIfToBooleanTrue: | 753 case Bytecode::kJumpIfToBooleanTrue: |
761 return Bytecode::kJumpIfToBooleanTrueConstant; | 754 return Bytecode::kJumpIfToBooleanTrueConstant; |
762 case Bytecode::kJumpIfToBooleanFalse: | 755 case Bytecode::kJumpIfToBooleanFalse: |
763 return Bytecode::kJumpIfToBooleanFalseConstant; | 756 return Bytecode::kJumpIfToBooleanFalseConstant; |
764 case Bytecode::kJumpIfNull: | 757 case Bytecode::kJumpIfNull: |
765 return Bytecode::kJumpIfNullConstant; | 758 return Bytecode::kJumpIfNullConstant; |
766 case Bytecode::kJumpIfUndefined: | 759 case Bytecode::kJumpIfUndefined: |
767 return Bytecode::kJumpIfUndefinedConstant; | 760 return Bytecode::kJumpIfUndefinedConstant; |
768 default: | 761 default: |
769 UNREACHABLE(); | 762 UNREACHABLE(); |
770 return Bytecode::kJumpConstant; | 763 return static_cast<Bytecode>(-1); |
771 } | 764 } |
772 } | 765 } |
773 | 766 |
774 | 767 |
775 void BytecodeArrayBuilder::PatchJump( | 768 // static |
776 const ZoneVector<uint8_t>::iterator& jump_target, | 769 Bytecode BytecodeArrayBuilder::GetJumpWithConstantWideOperand( |
777 ZoneVector<uint8_t>::iterator jump_location) { | 770 Bytecode jump_bytecode) { |
778 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); | 771 switch (jump_bytecode) { |
779 int delta = static_cast<int>(jump_target - jump_location); | 772 case Bytecode::kJump: |
780 | 773 return Bytecode::kJumpConstantWide; |
781 DCHECK(Bytecodes::IsJump(jump_bytecode)); | 774 case Bytecode::kJumpIfTrue: |
782 DCHECK_EQ(Bytecodes::Size(jump_bytecode), 2); | 775 return Bytecode::kJumpIfTrueConstantWide; |
783 DCHECK_NE(delta, 0); | 776 case Bytecode::kJumpIfFalse: |
784 | 777 return Bytecode::kJumpIfFalseConstantWide; |
785 if (FitsInImm8Operand(delta)) { | 778 case Bytecode::kJumpIfToBooleanTrue: |
786 // Just update the operand | 779 return Bytecode::kJumpIfToBooleanTrueConstantWide; |
787 jump_location++; | 780 case Bytecode::kJumpIfToBooleanFalse: |
788 *jump_location = static_cast<uint8_t>(delta); | 781 return Bytecode::kJumpIfToBooleanFalseConstantWide; |
789 } else { | 782 case Bytecode::kJumpIfNull: |
790 // Update the jump type and operand | 783 return Bytecode::kJumpIfNullConstantWide; |
791 size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); | 784 case Bytecode::kJumpIfUndefined: |
792 if (FitsInIdx8Operand(entry)) { | 785 return Bytecode::kJumpIfUndefinedConstantWide; |
793 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); | 786 default: |
794 *jump_location++ = Bytecodes::ToByte(jump_bytecode); | 787 UNREACHABLE(); |
795 *jump_location = static_cast<uint8_t>(entry); | 788 return static_cast<Bytecode>(-1); |
796 } else { | |
797 // TODO(oth): OutputJump should reserve a constant pool entry | |
798 // when jump is written. The reservation should be used here if | |
799 // needed, or cancelled if not. This is due to the patch needing | |
800 // to match the size of the code it's replacing. In future, | |
801 // there will probably be a jump with 32-bit operand for cases | |
802 // when constant pool is full, but that needs to be emitted in | |
803 // OutputJump too. | |
804 UNIMPLEMENTED(); | |
805 } | |
806 } | 789 } |
807 unbound_jumps_--; | |
808 } | 790 } |
809 | 791 |
810 | 792 |
811 // static | 793 // static |
812 Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { | 794 Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { |
813 switch (jump_bytecode) { | 795 switch (jump_bytecode) { |
814 case Bytecode::kJump: | 796 case Bytecode::kJump: |
815 case Bytecode::kJumpIfNull: | 797 case Bytecode::kJumpIfNull: |
816 case Bytecode::kJumpIfUndefined: | 798 case Bytecode::kJumpIfUndefined: |
817 return jump_bytecode; | 799 return jump_bytecode; |
818 case Bytecode::kJumpIfTrue: | 800 case Bytecode::kJumpIfTrue: |
819 return Bytecode::kJumpIfToBooleanTrue; | 801 return Bytecode::kJumpIfToBooleanTrue; |
820 case Bytecode::kJumpIfFalse: | 802 case Bytecode::kJumpIfFalse: |
821 return Bytecode::kJumpIfToBooleanFalse; | 803 return Bytecode::kJumpIfToBooleanFalse; |
822 default: | 804 default: |
823 UNREACHABLE(); | 805 UNREACHABLE(); |
824 } | 806 } |
825 return static_cast<Bytecode>(-1); | 807 return static_cast<Bytecode>(-1); |
826 } | 808 } |
827 | 809 |
828 | 810 |
| 811 void BytecodeArrayBuilder::PatchIndirectJumpWith8BitOperand( |
| 812 const ZoneVector<uint8_t>::iterator& jump_location, int delta) { |
| 813 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); |
| 814 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); |
| 815 ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; |
| 816 DCHECK_EQ(*operand_location, 0); |
| 817 if (FitsInImm8Operand(delta)) { |
| 818 // The jump fits within the range of an Imm8 operand, so cancel |
| 819 // the reservation and jump directly. |
| 820 constant_array_builder()->DiscardReservedEntry(OperandSize::kByte); |
| 821 *operand_location = static_cast<uint8_t>(delta); |
| 822 } else { |
| 823 // The jump does not fit within the range of an Imm8 operand, so |
| 824 // commit reservation putting the offset into the constant pool, |
| 825 // and update the jump instruction and operand. |
| 826 size_t entry = constant_array_builder()->CommitReservedEntry( |
| 827 OperandSize::kByte, handle(Smi::FromInt(delta), isolate())); |
| 828 DCHECK(FitsInIdx8Operand(entry)); |
| 829 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); |
| 830 *jump_location = Bytecodes::ToByte(jump_bytecode); |
| 831 *operand_location = static_cast<uint8_t>(entry); |
| 832 } |
| 833 } |
| 834 |
| 835 |
| 836 void BytecodeArrayBuilder::PatchIndirectJumpWith16BitOperand( |
| 837 const ZoneVector<uint8_t>::iterator& jump_location, int delta) { |
| 838 DCHECK(Bytecodes::IsJumpConstantWide(Bytecodes::FromByte(*jump_location))); |
| 839 ZoneVector<uint8_t>::iterator operand_location = jump_location + 1; |
| 840 size_t entry = constant_array_builder()->CommitReservedEntry( |
| 841 OperandSize::kShort, handle(Smi::FromInt(delta), isolate())); |
| 842 DCHECK(FitsInIdx16Operand(entry)); |
| 843 uint8_t operand_bytes[2]; |
| 844 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); |
| 845 DCHECK(*operand_location == 0 && *(operand_location + 1) == 0); |
| 846 *operand_location++ = operand_bytes[0]; |
| 847 *operand_location = operand_bytes[1]; |
| 848 } |
| 849 |
| 850 |
| 851 void BytecodeArrayBuilder::PatchJump( |
| 852 const ZoneVector<uint8_t>::iterator& jump_target, |
| 853 const ZoneVector<uint8_t>::iterator& jump_location) { |
| 854 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); |
| 855 int delta = static_cast<int>(jump_target - jump_location); |
| 856 DCHECK(Bytecodes::IsJump(jump_bytecode)); |
| 857 switch (Bytecodes::GetOperandSize(jump_bytecode, 0)) { |
| 858 case OperandSize::kByte: |
| 859 PatchIndirectJumpWith8BitOperand(jump_location, delta); |
| 860 break; |
| 861 case OperandSize::kShort: |
| 862 PatchIndirectJumpWith16BitOperand(jump_location, delta); |
| 863 break; |
| 864 case OperandSize::kNone: |
| 865 UNREACHABLE(); |
| 866 } |
| 867 unbound_jumps_--; |
| 868 } |
| 869 |
| 870 |
829 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, | 871 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, |
830 BytecodeLabel* label) { | 872 BytecodeLabel* label) { |
831 // Don't emit dead code. | 873 // Don't emit dead code. |
832 if (exit_seen_in_block_) return *this; | 874 if (exit_seen_in_block_) return *this; |
833 | 875 |
834 // Check if the value in accumulator is boolean, if not choose an | 876 // Check if the value in accumulator is boolean, if not choose an |
835 // appropriate JumpIfToBoolean bytecode. | 877 // appropriate JumpIfToBoolean bytecode. |
836 if (NeedToBooleanCast()) { | 878 if (NeedToBooleanCast()) { |
837 jump_bytecode = GetJumpWithToBoolean(jump_bytecode); | 879 jump_bytecode = GetJumpWithToBoolean(jump_bytecode); |
838 } | 880 } |
839 | 881 |
840 int delta; | |
841 if (label->is_bound()) { | 882 if (label->is_bound()) { |
842 // Label has been bound already so this is a backwards jump. | 883 // Label has been bound already so this is a backwards jump. |
843 CHECK_GE(bytecodes()->size(), label->offset()); | 884 CHECK_GE(bytecodes()->size(), label->offset()); |
844 CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); | 885 CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); |
845 size_t abs_delta = bytecodes()->size() - label->offset(); | 886 size_t abs_delta = bytecodes()->size() - label->offset(); |
846 delta = -static_cast<int>(abs_delta); | 887 int delta = -static_cast<int>(abs_delta); |
| 888 |
| 889 if (FitsInImm8Operand(delta)) { |
| 890 Output(jump_bytecode, static_cast<uint8_t>(delta)); |
| 891 } else { |
| 892 size_t entry = |
| 893 GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); |
| 894 if (FitsInIdx8Operand(entry)) { |
| 895 Output(GetJumpWithConstantOperand(jump_bytecode), |
| 896 static_cast<uint8_t>(entry)); |
| 897 } else if (FitsInIdx16Operand(entry)) { |
| 898 Output(GetJumpWithConstantWideOperand(jump_bytecode), |
| 899 static_cast<uint16_t>(entry)); |
| 900 } else { |
| 901 UNREACHABLE(); |
| 902 } |
| 903 } |
847 } else { | 904 } else { |
848 // Label has not yet been bound so this is a forward reference | 905 // The label has not yet been bound so this is a forward reference |
849 // that will be patched when the label is bound. | 906 // that will be patched when the label is bound. We create a |
| 907 // reservation in the constant pool so the jump can be patched |
| 908 // when the label is bound. The reservation means the maximum size |
| 909 // of the operand for the constant is known and the jump can |
| 910 // be emitted into the bytecode stream with space for the operand. |
850 label->set_referrer(bytecodes()->size()); | 911 label->set_referrer(bytecodes()->size()); |
851 delta = 0; | |
852 unbound_jumps_++; | 912 unbound_jumps_++; |
853 } | 913 OperandSize reserved_operand_size = |
854 | 914 constant_array_builder()->CreateReservedEntry(); |
855 if (FitsInImm8Operand(delta)) { | 915 switch (reserved_operand_size) { |
856 Output(jump_bytecode, static_cast<uint8_t>(delta)); | 916 case OperandSize::kByte: |
857 } else { | 917 Output(jump_bytecode, 0); |
858 size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); | 918 break; |
859 if (FitsInIdx8Operand(entry)) { | 919 case OperandSize::kShort: |
860 Output(GetJumpWithConstantOperand(jump_bytecode), | 920 Output(GetJumpWithConstantWideOperand(jump_bytecode), 0); |
861 static_cast<uint8_t>(entry)); | 921 break; |
862 } else { | 922 case OperandSize::kNone: |
863 UNIMPLEMENTED(); | 923 UNREACHABLE(); |
864 } | 924 } |
865 } | 925 } |
866 LeaveBasicBlock(); | 926 LeaveBasicBlock(); |
867 return *this; | 927 return *this; |
868 } | 928 } |
869 | 929 |
870 | 930 |
871 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { | 931 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { |
872 return OutputJump(Bytecode::kJump, label); | 932 return OutputJump(Bytecode::kJump, label); |
873 } | 933 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1019 } | 1079 } |
1020 | 1080 |
1021 | 1081 |
1022 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { | 1082 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { |
1023 Output(Bytecode::kDeleteLookupSlot); | 1083 Output(Bytecode::kDeleteLookupSlot); |
1024 return *this; | 1084 return *this; |
1025 } | 1085 } |
1026 | 1086 |
1027 | 1087 |
1028 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { | 1088 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { |
1029 // These constants shouldn't be added to the constant pool, the should use | 1089 return constant_array_builder()->Insert(object); |
1030 // specialzed bytecodes instead. | |
1031 DCHECK(!object.is_identical_to(isolate_->factory()->undefined_value())); | |
1032 DCHECK(!object.is_identical_to(isolate_->factory()->null_value())); | |
1033 DCHECK(!object.is_identical_to(isolate_->factory()->the_hole_value())); | |
1034 DCHECK(!object.is_identical_to(isolate_->factory()->true_value())); | |
1035 DCHECK(!object.is_identical_to(isolate_->factory()->false_value())); | |
1036 | |
1037 size_t* entry = constants_map_.Find(object); | |
1038 if (!entry) { | |
1039 entry = constants_map_.Get(object); | |
1040 *entry = constants_.size(); | |
1041 constants_.push_back(object); | |
1042 } | |
1043 DCHECK(constants_[*entry].is_identical_to(object)); | |
1044 return *entry; | |
1045 } | 1090 } |
1046 | 1091 |
1047 | 1092 |
1048 int BytecodeArrayBuilder::BorrowTemporaryRegister() { | 1093 int BytecodeArrayBuilder::BorrowTemporaryRegister() { |
1049 if (free_temporaries_.empty()) { | 1094 if (free_temporaries_.empty()) { |
1050 temporary_register_count_ += 1; | 1095 temporary_register_count_ += 1; |
1051 return last_temporary_register().index(); | 1096 return last_temporary_register().index(); |
1052 } else { | 1097 } else { |
1053 auto pos = free_temporaries_.begin(); | 1098 auto pos = free_temporaries_.begin(); |
1054 int retval = *pos; | 1099 int retval = *pos; |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1587 DCHECK_GT(next_consecutive_count_, 0); | 1632 DCHECK_GT(next_consecutive_count_, 0); |
1588 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); | 1633 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); |
1589 allocated_.push_back(next_consecutive_register_); | 1634 allocated_.push_back(next_consecutive_register_); |
1590 next_consecutive_count_--; | 1635 next_consecutive_count_--; |
1591 return Register(next_consecutive_register_++); | 1636 return Register(next_consecutive_register_++); |
1592 } | 1637 } |
1593 | 1638 |
1594 } // namespace interpreter | 1639 } // namespace interpreter |
1595 } // namespace internal | 1640 } // namespace internal |
1596 } // namespace v8 | 1641 } // namespace v8 |
OLD | NEW |