Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
6 : #define V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
7 :
8 : #include "src/base/compiler-specific.h"
9 : #include "src/globals.h"
10 : #include "src/interpreter/bytecode-register-allocator.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 : namespace interpreter {
15 :
16 : // An optimization stage for eliminating unnecessary transfers between
17 : // registers. The bytecode generator uses temporary registers
18 : // liberally for correctness and convenience and this stage removes
19 : // transfers that are not required and preserves correctness.
20 : class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
21 : : public NON_EXPORTED_BASE(BytecodeRegisterAllocator::Observer),
22 : public NON_EXPORTED_BASE(ZoneObject) {
23 : public:
24 : class BytecodeWriter {
25 : public:
26 2138306 : BytecodeWriter() = default;
27 8 : virtual ~BytecodeWriter() = default;
28 :
29 : // Called to emit a register transfer bytecode.
30 : virtual void EmitLdar(Register input) = 0;
31 : virtual void EmitStar(Register output) = 0;
32 : virtual void EmitMov(Register input, Register output) = 0;
33 :
34 : private:
35 : DISALLOW_COPY_AND_ASSIGN(BytecodeWriter);
36 : };
37 :
38 : BytecodeRegisterOptimizer(Zone* zone,
39 : BytecodeRegisterAllocator* register_allocator,
40 : int fixed_registers_count, int parameter_count,
41 : BytecodeWriter* bytecode_writer);
42 0 : ~BytecodeRegisterOptimizer() override = default;
43 :
44 : // Perform explicit register transfer operations.
45 : void DoLdar(Register input) {
46 : // TODO(rmcilroy): Avoid treating accumulator loads as clobbering the
47 : // accumulator until the value is actually materialized in the accumulator.
48 : RegisterInfo* input_info = GetRegisterInfo(input);
49 7828550 : RegisterTransfer(input_info, accumulator_info_);
50 : }
51 : void DoStar(Register output) {
52 : RegisterInfo* output_info = GetRegisterInfo(output);
53 25475958 : RegisterTransfer(accumulator_info_, output_info);
54 : }
55 735577 : void DoMov(Register input, Register output) {
56 : RegisterInfo* input_info = GetRegisterInfo(input);
57 : RegisterInfo* output_info = GetRegisterInfo(output);
58 735577 : RegisterTransfer(input_info, output_info);
59 735595 : }
60 :
61 : // Materialize all live registers and flush equivalence sets.
62 : void Flush();
63 : bool EnsureAllRegistersAreFlushed() const;
64 :
65 : // Prepares for |bytecode|.
66 : template <Bytecode bytecode, AccumulatorUse accumulator_use>
67 : V8_INLINE void PrepareForBytecode() {
68 : if (Bytecodes::IsJump(bytecode) || Bytecodes::IsSwitch(bytecode) ||
69 : bytecode == Bytecode::kDebugger ||
70 : bytecode == Bytecode::kSuspendGenerator ||
71 : bytecode == Bytecode::kResumeGenerator) {
72 : // All state must be flushed before emitting
73 : // - a jump bytecode (as the register equivalents at the jump target
74 : // aren't known)
75 : // - a switch bytecode (as the register equivalents at the switch targets
76 : // aren't known)
77 : // - a call to the debugger (as it can manipulate locals and parameters),
78 : // - a generator suspend (as this involves saving all registers).
79 : // - a generator register restore.
80 2177782 : Flush();
81 : }
82 :
83 : // Materialize the accumulator if it is read by the bytecode. The
84 : // accumulator is special and no other register can be materialized
85 : // in it's place.
86 : if (BytecodeOperands::ReadsAccumulator(accumulator_use)) {
87 17256657 : Materialize(accumulator_info_);
88 : }
89 :
90 : // Materialize an equivalent to the accumulator if it will be
91 : // clobbered when the bytecode is dispatched.
92 : if (BytecodeOperands::WritesAccumulator(accumulator_use)) {
93 39964959 : PrepareOutputRegister(accumulator_);
94 : }
95 : }
96 :
97 : // Prepares |reg| for being used as an output operand.
98 : void PrepareOutputRegister(Register reg);
99 :
100 : // Prepares registers in |reg_list| for being used as an output operand.
101 : void PrepareOutputRegisterList(RegisterList reg_list);
102 :
103 : // Returns an equivalent register to |reg| to be used as an input operand.
104 : Register GetInputRegister(Register reg);
105 :
106 : // Returns an equivalent register list to |reg_list| to be used as an input
107 : // operand.
108 : RegisterList GetInputRegisterList(RegisterList reg_list);
109 :
110 : int maxiumum_register_index() const { return max_register_index_; }
111 :
112 : private:
113 : static const uint32_t kInvalidEquivalenceId;
114 :
115 : class RegisterInfo;
116 :
117 : // BytecodeRegisterAllocator::Observer interface.
118 : void RegisterAllocateEvent(Register reg) override;
119 : void RegisterListAllocateEvent(RegisterList reg_list) override;
120 : void RegisterListFreeEvent(RegisterList reg) override;
121 :
122 : // Update internal state for register transfer from |input| to |output|
123 : void RegisterTransfer(RegisterInfo* input, RegisterInfo* output);
124 :
125 : // Emit a register transfer bytecode from |input| to |output|.
126 : void OutputRegisterTransfer(RegisterInfo* input, RegisterInfo* output);
127 :
128 : void CreateMaterializedEquivalent(RegisterInfo* info);
129 : RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
130 : RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
131 : void Materialize(RegisterInfo* info);
132 : void AddToEquivalenceSet(RegisterInfo* set_member,
133 : RegisterInfo* non_set_member);
134 :
135 : void PushToRegistersNeedingFlush(RegisterInfo* reg);
136 : // Methods for finding and creating metadata for each register.
137 : RegisterInfo* GetRegisterInfo(Register reg) {
138 : size_t index = GetRegisterInfoTableIndex(reg);
139 : DCHECK_LT(index, register_info_table_.size());
140 127679135 : return register_info_table_[index];
141 : }
142 21830672 : RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
143 : size_t index = GetRegisterInfoTableIndex(reg);
144 : return index < register_info_table_.size() ? register_info_table_[index]
145 59486931 : : NewRegisterInfo(reg);
146 : }
147 : RegisterInfo* NewRegisterInfo(Register reg) {
148 : size_t index = GetRegisterInfoTableIndex(reg);
149 : DCHECK_GE(index, register_info_table_.size());
150 6005099 : GrowRegisterMap(reg);
151 6005113 : return register_info_table_[index];
152 : }
153 :
154 : void GrowRegisterMap(Register reg);
155 :
156 : bool RegisterIsTemporary(Register reg) const {
157 : return reg >= temporary_base_;
158 : }
159 :
160 : bool RegisterIsObservable(Register reg) const {
161 99538370 : return reg != accumulator_ && !RegisterIsTemporary(reg);
162 : }
163 :
164 : static Register OperandToRegister(uint32_t operand) {
165 : return Register::FromOperand(static_cast<int32_t>(operand));
166 : }
167 :
168 : size_t GetRegisterInfoTableIndex(Register reg) const {
169 156213912 : return static_cast<size_t>(reg.index() + register_info_table_offset_);
170 : }
171 :
172 : Register RegisterFromRegisterInfoTableIndex(size_t index) const {
173 26596418 : return Register(static_cast<int>(index) - register_info_table_offset_);
174 : }
175 :
176 : uint32_t NextEquivalenceId() {
177 74250939 : equivalence_id_++;
178 : // TODO(rmcilroy): use the same type for these and remove static_cast.
179 74250939 : CHECK_NE(static_cast<size_t>(equivalence_id_), kInvalidEquivalenceId);
180 74250939 : return equivalence_id_;
181 : }
182 :
183 : void AllocateRegister(RegisterInfo* info);
184 :
185 : Zone* zone() { return zone_; }
186 :
187 : const Register accumulator_;
188 : RegisterInfo* accumulator_info_;
189 : const Register temporary_base_;
190 : int max_register_index_;
191 :
192 : // Direct mapping to register info.
193 : ZoneVector<RegisterInfo*> register_info_table_;
194 : int register_info_table_offset_;
195 :
196 : ZoneDeque<RegisterInfo*> registers_needing_flushed_;
197 :
198 : // Counter for equivalence sets identifiers.
199 : int equivalence_id_;
200 :
201 : BytecodeWriter* bytecode_writer_;
202 : bool flush_required_;
203 : Zone* zone_;
204 :
205 : DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterOptimizer);
206 : };
207 :
208 : } // namespace interpreter
209 : } // namespace internal
210 : } // namespace v8
211 :
212 : #endif // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
|