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

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: Rebase. 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
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, 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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698