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, TENURED); |
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 579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
751 return Bytecode::kJumpIfNullConstant; | 744 return Bytecode::kJumpIfNullConstant; |
752 case Bytecode::kJumpIfUndefined: | 745 case Bytecode::kJumpIfUndefined: |
753 return Bytecode::kJumpIfUndefinedConstant; | 746 return Bytecode::kJumpIfUndefinedConstant; |
754 default: | 747 default: |
755 UNREACHABLE(); | 748 UNREACHABLE(); |
756 return Bytecode::kJumpConstant; | 749 return Bytecode::kJumpConstant; |
757 } | 750 } |
758 } | 751 } |
759 | 752 |
760 | 753 |
761 void BytecodeArrayBuilder::PatchJump( | 754 // static |
762 const ZoneVector<uint8_t>::iterator& jump_target, | 755 Bytecode BytecodeArrayBuilder::GetJumpWithConstantWideOperand( |
763 ZoneVector<uint8_t>::iterator jump_location) { | 756 Bytecode jump_bytecode) { |
764 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); | 757 switch (jump_bytecode) { |
765 int delta = static_cast<int>(jump_target - jump_location); | 758 case Bytecode::kJump: |
766 | 759 return Bytecode::kJumpConstantWide; |
767 DCHECK(Bytecodes::IsJump(jump_bytecode)); | 760 case Bytecode::kJumpIfTrue: |
768 DCHECK_EQ(Bytecodes::Size(jump_bytecode), 2); | 761 return Bytecode::kJumpIfTrueConstantWide; |
769 DCHECK_NE(delta, 0); | 762 case Bytecode::kJumpIfFalse: |
770 | 763 return Bytecode::kJumpIfFalseConstantWide; |
771 if (FitsInImm8Operand(delta)) { | 764 case Bytecode::kJumpIfToBooleanTrue: |
772 // Just update the operand | 765 return Bytecode::kJumpIfToBooleanTrueConstantWide; |
773 jump_location++; | 766 case Bytecode::kJumpIfToBooleanFalse: |
774 *jump_location = static_cast<uint8_t>(delta); | 767 return Bytecode::kJumpIfToBooleanFalseConstantWide; |
775 } else { | 768 case Bytecode::kJumpIfNull: |
776 // Update the jump type and operand | 769 return Bytecode::kJumpIfNullConstantWide; |
777 size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); | 770 case Bytecode::kJumpIfUndefined: |
778 if (FitsInIdx8Operand(entry)) { | 771 return Bytecode::kJumpIfUndefinedConstantWide; |
779 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); | 772 default: |
780 *jump_location++ = Bytecodes::ToByte(jump_bytecode); | 773 UNREACHABLE(); |
781 *jump_location = static_cast<uint8_t>(entry); | 774 return Bytecode::kJumpConstantWide; |
rmcilroy
2016/01/04 17:05:48
nit - return static_cast<Bytecode>(-1) (and above)
oth
2016/01/05 09:30:08
Done.
| |
782 } else { | |
783 // TODO(oth): OutputJump should reserve a constant pool entry | |
784 // when jump is written. The reservation should be used here if | |
785 // needed, or cancelled if not. This is due to the patch needing | |
786 // to match the size of the code it's replacing. In future, | |
787 // there will probably be a jump with 32-bit operand for cases | |
788 // when constant pool is full, but that needs to be emitted in | |
789 // OutputJump too. | |
790 UNIMPLEMENTED(); | |
791 } | |
792 } | 775 } |
793 unbound_jumps_--; | |
794 } | 776 } |
795 | 777 |
796 | 778 |
797 // static | 779 // static |
798 Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { | 780 Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) { |
799 switch (jump_bytecode) { | 781 switch (jump_bytecode) { |
800 case Bytecode::kJump: | 782 case Bytecode::kJump: |
801 case Bytecode::kJumpIfNull: | 783 case Bytecode::kJumpIfNull: |
802 case Bytecode::kJumpIfUndefined: | 784 case Bytecode::kJumpIfUndefined: |
803 return jump_bytecode; | 785 return jump_bytecode; |
804 case Bytecode::kJumpIfTrue: | 786 case Bytecode::kJumpIfTrue: |
805 return Bytecode::kJumpIfToBooleanTrue; | 787 return Bytecode::kJumpIfToBooleanTrue; |
806 case Bytecode::kJumpIfFalse: | 788 case Bytecode::kJumpIfFalse: |
807 return Bytecode::kJumpIfToBooleanFalse; | 789 return Bytecode::kJumpIfToBooleanFalse; |
808 default: | 790 default: |
809 UNREACHABLE(); | 791 UNREACHABLE(); |
810 } | 792 } |
811 return static_cast<Bytecode>(-1); | 793 return static_cast<Bytecode>(-1); |
812 } | 794 } |
813 | 795 |
814 | 796 |
797 void BytecodeArrayBuilder::PatchJump( | |
798 const ZoneVector<uint8_t>::iterator& jump_target, | |
799 const ZoneVector<uint8_t>::iterator& jump_location) { | |
800 int delta = static_cast<int>(jump_target - jump_location); | |
801 Bytecode jump_bytecode = Bytecodes::FromByte(*jump_location); | |
802 auto operand_location = jump_location + 1; | |
rmcilroy
2016/01/04 17:05:48
Don't use auto here (it's not immediately obvious
oth
2016/01/05 09:30:08
Done.
| |
803 auto reservation_token = | |
804 static_cast<ConstantArrayBuilder::ReservationToken>(*operand_location); | |
rmcilroy
2016/01/04 17:05:48
Could we wrap up this ReservationToken getter stuf
oth
2016/01/05 09:30:08
Simplified the code path.
| |
805 if (ConstantArrayBuilder::ReservationToken::kIdx8 == reservation_token) { | |
rmcilroy
2016/01/04 17:05:48
nit - switch on ReservationToken type
oth
2016/01/05 09:30:08
Done. Moved the switch bodies into separate functi
| |
806 DCHECK(Bytecodes::IsJumpImmediate(jump_bytecode)); | |
807 if (FitsInImm8Operand(delta)) { | |
808 // The jump fits with the range of an Imm8 operand, so cancel | |
809 // the reservation and jump directly. | |
810 constant_array_builder()->DiscardReservedEntry(reservation_token); | |
811 *operand_location = static_cast<uint8_t>(delta); | |
812 } else { | |
813 // The jump does not fit in range of an Imm8 operand, so commit | |
814 // reservation and update the jump instruction and operand. | |
815 size_t entry = constant_array_builder()->CommitReservedEntry( | |
816 reservation_token, handle(Smi::FromInt(delta), isolate())); | |
817 DCHECK(FitsInIdx8Operand(entry)); | |
818 jump_bytecode = GetJumpWithConstantOperand(jump_bytecode); | |
819 *jump_location = Bytecodes::ToByte(jump_bytecode); | |
820 *operand_location = static_cast<uint8_t>(entry); | |
821 } | |
822 } else { | |
823 // A reservation for an entry in the constant array with a 16-bit index. | |
824 DCHECK(ConstantArrayBuilder::ReservationToken::kIdx16 == reservation_token); | |
825 DCHECK(Bytecodes::IsJumpConstantWide(jump_bytecode)); | |
826 size_t entry = constant_array_builder()->CommitReservedEntry( | |
827 reservation_token, handle(Smi::FromInt(delta), isolate())); | |
828 DCHECK(FitsInIdx16Operand(entry)); | |
829 uint8_t operand_bytes[2]; | |
830 WriteUnalignedUInt16(operand_bytes, static_cast<uint16_t>(entry)); | |
831 *operand_location++ = operand_bytes[0]; | |
832 *operand_location = operand_bytes[1]; | |
833 } | |
834 unbound_jumps_--; | |
835 } | |
836 | |
837 | |
815 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, | 838 BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, |
816 BytecodeLabel* label) { | 839 BytecodeLabel* label) { |
817 // Don't emit dead code. | 840 // Don't emit dead code. |
818 if (exit_seen_in_block_) return *this; | 841 if (exit_seen_in_block_) return *this; |
819 | 842 |
820 // Check if the value in accumulator is boolean, if not choose an | 843 // Check if the value in accumulator is boolean, if not choose an |
821 // appropriate JumpIfToBoolean bytecode. | 844 // appropriate JumpIfToBoolean bytecode. |
822 if (NeedToBooleanCast()) { | 845 if (NeedToBooleanCast()) { |
823 jump_bytecode = GetJumpWithToBoolean(jump_bytecode); | 846 jump_bytecode = GetJumpWithToBoolean(jump_bytecode); |
824 } | 847 } |
825 | 848 |
826 int delta; | |
827 if (label->is_bound()) { | 849 if (label->is_bound()) { |
828 // Label has been bound already so this is a backwards jump. | 850 // Label has been bound already so this is a backwards jump. |
829 CHECK_GE(bytecodes()->size(), label->offset()); | 851 CHECK_GE(bytecodes()->size(), label->offset()); |
830 CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); | 852 CHECK_LE(bytecodes()->size(), static_cast<size_t>(kMaxInt)); |
831 size_t abs_delta = bytecodes()->size() - label->offset(); | 853 size_t abs_delta = bytecodes()->size() - label->offset(); |
832 delta = -static_cast<int>(abs_delta); | 854 int delta = -static_cast<int>(abs_delta); |
855 | |
856 if (FitsInImm8Operand(delta)) { | |
857 Output(jump_bytecode, static_cast<uint8_t>(delta)); | |
858 } else { | |
859 size_t entry = | |
860 GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); | |
861 if (FitsInIdx8Operand(entry)) { | |
862 Output(GetJumpWithConstantOperand(jump_bytecode), | |
863 static_cast<uint8_t>(entry)); | |
864 } else if (FitsInIdx16Operand(entry)) { | |
865 Output(GetJumpWithConstantWideOperand(jump_bytecode), | |
866 static_cast<uint16_t>(entry)); | |
867 } else { | |
868 UNREACHABLE(); | |
869 } | |
870 } | |
833 } else { | 871 } else { |
834 // Label has not yet been bound so this is a forward reference | 872 // Label has not yet been bound so this is a forward reference |
835 // that will be patched when the label is bound. | 873 // that will be patched when the label is bound. |
836 label->set_referrer(bytecodes()->size()); | 874 label->set_referrer(bytecodes()->size()); |
837 delta = 0; | |
838 unbound_jumps_++; | 875 unbound_jumps_++; |
876 auto token = constant_array_builder()->CreateReservedEntry(); | |
rmcilroy
2016/01/04 17:05:48
don't use auto here (not immediately clear what th
oth
2016/01/05 09:30:08
Done.
| |
877 switch (token) { | |
rmcilroy
2016/01/04 17:05:48
Please add a comment mentioning what you are doing
oth
2016/01/05 09:30:08
Removed. The token was supposed to be symbolic - m
| |
878 case ConstantArrayBuilder::ReservationToken::kIdx8: { | |
879 Output(jump_bytecode, static_cast<uint8_t>(token)); | |
880 break; | |
881 } | |
882 case ConstantArrayBuilder::ReservationToken::kIdx16: { | |
883 uint16_t target = static_cast<uint16_t>(token); | |
884 target |= target << 8; | |
rmcilroy
2016/01/04 17:05:48
nit - I assume this is for big endian support? Ple
oth
2016/01/05 09:30:08
Yes. No longer exists.
| |
885 Output(GetJumpWithConstantWideOperand(jump_bytecode), target); | |
886 break; | |
887 } | |
888 } | |
839 } | 889 } |
840 | 890 |
841 if (FitsInImm8Operand(delta)) { | |
842 Output(jump_bytecode, static_cast<uint8_t>(delta)); | |
843 } else { | |
844 size_t entry = GetConstantPoolEntry(handle(Smi::FromInt(delta), isolate())); | |
845 if (FitsInIdx8Operand(entry)) { | |
846 Output(GetJumpWithConstantOperand(jump_bytecode), | |
847 static_cast<uint8_t>(entry)); | |
848 } else { | |
849 UNIMPLEMENTED(); | |
850 } | |
851 } | |
852 LeaveBasicBlock(); | 891 LeaveBasicBlock(); |
853 return *this; | 892 return *this; |
854 } | 893 } |
855 | 894 |
856 | 895 |
857 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { | 896 BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) { |
858 return OutputJump(Bytecode::kJump, label); | 897 return OutputJump(Bytecode::kJump, label); |
859 } | 898 } |
860 | 899 |
861 | 900 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1005 } | 1044 } |
1006 | 1045 |
1007 | 1046 |
1008 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { | 1047 BytecodeArrayBuilder& BytecodeArrayBuilder::DeleteLookupSlot() { |
1009 Output(Bytecode::kDeleteLookupSlot); | 1048 Output(Bytecode::kDeleteLookupSlot); |
1010 return *this; | 1049 return *this; |
1011 } | 1050 } |
1012 | 1051 |
1013 | 1052 |
1014 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { | 1053 size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) { |
1015 // These constants shouldn't be added to the constant pool, the should use | 1054 return constant_array_builder()->Insert(object); |
1016 // specialzed bytecodes instead. | |
1017 DCHECK(!object.is_identical_to(isolate_->factory()->undefined_value())); | |
1018 DCHECK(!object.is_identical_to(isolate_->factory()->null_value())); | |
1019 DCHECK(!object.is_identical_to(isolate_->factory()->the_hole_value())); | |
1020 DCHECK(!object.is_identical_to(isolate_->factory()->true_value())); | |
1021 DCHECK(!object.is_identical_to(isolate_->factory()->false_value())); | |
1022 | |
1023 size_t* entry = constants_map_.Find(object); | |
1024 if (!entry) { | |
1025 entry = constants_map_.Get(object); | |
1026 *entry = constants_.size(); | |
1027 constants_.push_back(object); | |
1028 } | |
1029 DCHECK(constants_[*entry].is_identical_to(object)); | |
1030 return *entry; | |
1031 } | 1055 } |
1032 | 1056 |
1033 | 1057 |
1034 int BytecodeArrayBuilder::BorrowTemporaryRegister() { | 1058 int BytecodeArrayBuilder::BorrowTemporaryRegister() { |
1035 if (free_temporaries_.empty()) { | 1059 if (free_temporaries_.empty()) { |
1036 temporary_register_count_ += 1; | 1060 temporary_register_count_ += 1; |
1037 return last_temporary_register().index(); | 1061 return last_temporary_register().index(); |
1038 } else { | 1062 } else { |
1039 auto pos = free_temporaries_.begin(); | 1063 auto pos = free_temporaries_.begin(); |
1040 int retval = *pos; | 1064 int retval = *pos; |
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1543 DCHECK_GT(next_consecutive_count_, 0); | 1567 DCHECK_GT(next_consecutive_count_, 0); |
1544 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); | 1568 builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_); |
1545 allocated_.push_back(next_consecutive_register_); | 1569 allocated_.push_back(next_consecutive_register_); |
1546 next_consecutive_count_--; | 1570 next_consecutive_count_--; |
1547 return Register(next_consecutive_register_++); | 1571 return Register(next_consecutive_register_++); |
1548 } | 1572 } |
1549 | 1573 |
1550 } // namespace interpreter | 1574 } // namespace interpreter |
1551 } // namespace internal | 1575 } // namespace internal |
1552 } // namespace v8 | 1576 } // namespace v8 |
OLD | NEW |