Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: src/interpreter/bytecode-array-builder.cc

Issue 1546683002: [Interpreter] Add support for jumps using constants with wide operands. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Incorporate comments on patchset 13. Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/interpreter/bytecode-array-builder.h ('k') | src/interpreter/bytecode-array-iterator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-array-builder.h ('k') | src/interpreter/bytecode-array-iterator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698