V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
bytecode-register-optimizer.h
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:
25  public:
26  BytecodeWriter() = default;
27  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 
39  BytecodeRegisterAllocator* register_allocator,
40  int fixed_registers_count, int parameter_count,
41  BytecodeWriter* bytecode_writer);
42  ~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  RegisterTransfer(input_info, accumulator_info_);
50  }
51  void DoStar(Register output) {
52  RegisterInfo* output_info = GetRegisterInfo(output);
53  RegisterTransfer(accumulator_info_, output_info);
54  }
55  void DoMov(Register input, Register output) {
56  RegisterInfo* input_info = GetRegisterInfo(input);
57  RegisterInfo* output_info = GetRegisterInfo(output);
58  RegisterTransfer(input_info, output_info);
59  }
60 
61  // Materialize all live registers and flush equivalence sets.
62  void Flush();
63 
64  // Prepares for |bytecode|.
65  template <Bytecode bytecode, AccumulatorUse accumulator_use>
66  V8_INLINE void PrepareForBytecode() {
67  if (Bytecodes::IsJump(bytecode) || Bytecodes::IsSwitch(bytecode) ||
68  bytecode == Bytecode::kDebugger ||
69  bytecode == Bytecode::kSuspendGenerator ||
70  bytecode == Bytecode::kResumeGenerator) {
71  // All state must be flushed before emitting
72  // - a jump bytecode (as the register equivalents at the jump target
73  // aren't known)
74  // - a switch bytecode (as the register equivalents at the switch targets
75  // aren't known)
76  // - a call to the debugger (as it can manipulate locals and parameters),
77  // - a generator suspend (as this involves saving all registers).
78  // - a generator register restore.
79  Flush();
80  }
81 
82  // Materialize the accumulator if it is read by the bytecode. The
83  // accumulator is special and no other register can be materialized
84  // in it's place.
85  if (BytecodeOperands::ReadsAccumulator(accumulator_use)) {
86  Materialize(accumulator_info_);
87  }
88 
89  // Materialize an equivalent to the accumulator if it will be
90  // clobbered when the bytecode is dispatched.
91  if (BytecodeOperands::WritesAccumulator(accumulator_use)) {
92  PrepareOutputRegister(accumulator_);
93  }
94  }
95 
96  // Prepares |reg| for being used as an output operand.
97  void PrepareOutputRegister(Register reg);
98 
99  // Prepares registers in |reg_list| for being used as an output operand.
100  void PrepareOutputRegisterList(RegisterList reg_list);
101 
102  // Returns an equivalent register to |reg| to be used as an input operand.
103  Register GetInputRegister(Register reg);
104 
105  // Returns an equivalent register list to |reg_list| to be used as an input
106  // operand.
107  RegisterList GetInputRegisterList(RegisterList reg_list);
108 
109  int maxiumum_register_index() const { return max_register_index_; }
110 
111  private:
112  static const uint32_t kInvalidEquivalenceId;
113 
114  class RegisterInfo;
115 
116  // BytecodeRegisterAllocator::Observer interface.
117  void RegisterAllocateEvent(Register reg) override;
118  void RegisterListAllocateEvent(RegisterList reg_list) override;
119  void RegisterListFreeEvent(RegisterList reg) override;
120 
121  // Update internal state for register transfer from |input| to |output|
122  void RegisterTransfer(RegisterInfo* input, RegisterInfo* output);
123 
124  // Emit a register transfer bytecode from |input| to |output|.
125  void OutputRegisterTransfer(RegisterInfo* input, RegisterInfo* output);
126 
127  void CreateMaterializedEquivalent(RegisterInfo* info);
128  RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
129  RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
130  void Materialize(RegisterInfo* info);
131  void AddToEquivalenceSet(RegisterInfo* set_member,
132  RegisterInfo* non_set_member);
133 
134  void PushToRegistersNeedingFlush(RegisterInfo* reg);
135  bool EnsureAllRegistersAreFlushed() const;
136 
137  // Methods for finding and creating metadata for each register.
138  RegisterInfo* GetRegisterInfo(Register reg) {
139  size_t index = GetRegisterInfoTableIndex(reg);
140  DCHECK_LT(index, register_info_table_.size());
141  return register_info_table_[index];
142  }
143  RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
144  size_t index = GetRegisterInfoTableIndex(reg);
145  return index < register_info_table_.size() ? register_info_table_[index]
146  : NewRegisterInfo(reg);
147  }
148  RegisterInfo* NewRegisterInfo(Register reg) {
149  size_t index = GetRegisterInfoTableIndex(reg);
150  DCHECK_GE(index, register_info_table_.size());
151  GrowRegisterMap(reg);
152  return register_info_table_[index];
153  }
154 
155  void GrowRegisterMap(Register reg);
156 
157  bool RegisterIsTemporary(Register reg) const {
158  return reg >= temporary_base_;
159  }
160 
161  bool RegisterIsObservable(Register reg) const {
162  return reg != accumulator_ && !RegisterIsTemporary(reg);
163  }
164 
165  static Register OperandToRegister(uint32_t operand) {
166  return Register::FromOperand(static_cast<int32_t>(operand));
167  }
168 
169  size_t GetRegisterInfoTableIndex(Register reg) const {
170  return static_cast<size_t>(reg.index() + register_info_table_offset_);
171  }
172 
173  Register RegisterFromRegisterInfoTableIndex(size_t index) const {
174  return Register(static_cast<int>(index) - register_info_table_offset_);
175  }
176 
177  uint32_t NextEquivalenceId() {
178  equivalence_id_++;
179  // TODO(rmcilroy): use the same type for these and remove static_cast.
180  CHECK_NE(static_cast<size_t>(equivalence_id_), kInvalidEquivalenceId);
181  return equivalence_id_;
182  }
183 
184  void AllocateRegister(RegisterInfo* info);
185 
186  Zone* zone() { return zone_; }
187 
188  const Register accumulator_;
189  RegisterInfo* accumulator_info_;
190  const Register temporary_base_;
191  int max_register_index_;
192 
193  // Direct mapping to register info.
194  ZoneVector<RegisterInfo*> register_info_table_;
195  int register_info_table_offset_;
196 
197  ZoneDeque<RegisterInfo*> registers_needing_flushed_;
198 
199  // Counter for equivalence sets identifiers.
200  int equivalence_id_;
201 
202  BytecodeWriter* bytecode_writer_;
203  bool flush_required_;
204  Zone* zone_;
205 
206  DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterOptimizer);
207 };
208 
209 } // namespace interpreter
210 } // namespace internal
211 } // namespace v8
212 
213 #endif // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
Definition: libplatform.h:13