• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-pipeline.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
NON_EXPORTED_BASE(BytecodeRegisterAllocator::Observer)21     : public NON_EXPORTED_BASE(BytecodeRegisterAllocator::Observer),
22       public NON_EXPORTED_BASE(ZoneObject) {
23  public:
24   BytecodeRegisterOptimizer(Zone* zone,
25                             BytecodeRegisterAllocator* register_allocator,
26                             int fixed_registers_count, int parameter_count,
27                             BytecodePipelineStage* next_stage);
28   virtual ~BytecodeRegisterOptimizer() {}
29 
30   // Perform explicit register transfer operations.
31   void DoLdar(Register input, BytecodeSourceInfo source_info) {
32     RegisterInfo* input_info = GetRegisterInfo(input);
33     RegisterTransfer(input_info, accumulator_info_, source_info);
34   }
35   void DoStar(Register output, BytecodeSourceInfo source_info) {
36     RegisterInfo* output_info = GetRegisterInfo(output);
37     RegisterTransfer(accumulator_info_, output_info, source_info);
38   }
39   void DoMov(Register input, Register output, BytecodeSourceInfo source_info) {
40     RegisterInfo* input_info = GetRegisterInfo(input);
41     RegisterInfo* output_info = GetRegisterInfo(output);
42     RegisterTransfer(input_info, output_info, source_info);
43   }
44 
45   // Materialize all live registers and flush equivalence sets.
46   void Flush();
47 
48   // Prepares for |bytecode|.
49   template <Bytecode bytecode, AccumulatorUse accumulator_use>
50   INLINE(void PrepareForBytecode()) {
51     if (Bytecodes::IsJump(bytecode) || bytecode == Bytecode::kDebugger ||
52         bytecode == Bytecode::kSuspendGenerator) {
53       // All state must be flushed before emitting
54       // - a jump bytecode (as the register equivalents at the jump target
55       // aren't
56       //   known.
57       // - a call to the debugger (as it can manipulate locals and parameters),
58       // - a generator suspend (as this involves saving all registers).
59       Flush();
60     }
61 
62     // Materialize the accumulator if it is read by the bytecode. The
63     // accumulator is special and no other register can be materialized
64     // in it's place.
65     if (BytecodeOperands::ReadsAccumulator(accumulator_use)) {
66       Materialize(accumulator_info_);
67     }
68 
69     // Materialize an equivalent to the accumulator if it will be
70     // clobbered when the bytecode is dispatched.
71     if (BytecodeOperands::WritesAccumulator(accumulator_use)) {
72       PrepareOutputRegister(accumulator_);
73     }
74   }
75 
76   // Prepares |reg| for being used as an output operand.
77   void PrepareOutputRegister(Register reg);
78 
79   // Prepares registers in |reg_list| for being used as an output operand.
80   void PrepareOutputRegisterList(RegisterList reg_list);
81 
82   // Returns an equivalent register to |reg| to be used as an input operand.
83   Register GetInputRegister(Register reg);
84 
85   // Returns an equivalent register list to |reg_list| to be used as an input
86   // operand.
87   RegisterList GetInputRegisterList(RegisterList reg_list);
88 
89   int maxiumum_register_index() const { return max_register_index_; }
90 
91  private:
92   static const uint32_t kInvalidEquivalenceId;
93 
94   class RegisterInfo;
95 
96   // BytecodeRegisterAllocator::Observer interface.
97   void RegisterAllocateEvent(Register reg) override;
98   void RegisterListAllocateEvent(RegisterList reg_list) override;
99   void RegisterListFreeEvent(RegisterList reg) override;
100 
101   // Update internal state for register transfer from |input| to
102   // |output| using |source_info| as source position information if
103   // any bytecodes are emitted due to transfer.
104   void RegisterTransfer(RegisterInfo* input, RegisterInfo* output,
105                         BytecodeSourceInfo source_info);
106 
107   // Emit a register transfer bytecode from |input| to |output|.
108   void OutputRegisterTransfer(
109       RegisterInfo* input, RegisterInfo* output,
110       BytecodeSourceInfo source_info = BytecodeSourceInfo());
111 
112   // Emits a Nop to preserve source position information in the
113   // bytecode pipeline.
114   void EmitNopForSourceInfo(BytecodeSourceInfo source_info) const;
115 
116   void CreateMaterializedEquivalent(RegisterInfo* info);
117   RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
118   RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
119   void Materialize(RegisterInfo* info);
120   void AddToEquivalenceSet(RegisterInfo* set_member,
121                            RegisterInfo* non_set_member);
122 
123   // Methods for finding and creating metadata for each register.
124   RegisterInfo* GetRegisterInfo(Register reg) {
125     size_t index = GetRegisterInfoTableIndex(reg);
126     DCHECK_LT(index, register_info_table_.size());
127     return register_info_table_[index];
128   }
129   RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
130     size_t index = GetRegisterInfoTableIndex(reg);
131     return index < register_info_table_.size() ? register_info_table_[index]
132                                                : NewRegisterInfo(reg);
133   }
134   RegisterInfo* NewRegisterInfo(Register reg) {
135     size_t index = GetRegisterInfoTableIndex(reg);
136     DCHECK_GE(index, register_info_table_.size());
137     GrowRegisterMap(reg);
138     return register_info_table_[index];
139   }
140 
141   void GrowRegisterMap(Register reg);
142 
143   bool RegisterIsTemporary(Register reg) const {
144     return reg >= temporary_base_;
145   }
146 
147   bool RegisterIsObservable(Register reg) const {
148     return reg != accumulator_ && !RegisterIsTemporary(reg);
149   }
150 
151   static Register OperandToRegister(uint32_t operand) {
152     return Register::FromOperand(static_cast<int32_t>(operand));
153   }
154 
155   size_t GetRegisterInfoTableIndex(Register reg) const {
156     return static_cast<size_t>(reg.index() + register_info_table_offset_);
157   }
158 
159   Register RegisterFromRegisterInfoTableIndex(size_t index) const {
160     return Register(static_cast<int>(index) - register_info_table_offset_);
161   }
162 
163   uint32_t NextEquivalenceId() {
164     equivalence_id_++;
165     // TODO(rmcilroy): use the same type for these and remove static_cast.
166     CHECK_NE(static_cast<size_t>(equivalence_id_), kInvalidEquivalenceId);
167     return equivalence_id_;
168   }
169 
170   Zone* zone() { return zone_; }
171 
172   const Register accumulator_;
173   RegisterInfo* accumulator_info_;
174   const Register temporary_base_;
175   int max_register_index_;
176 
177   // Direct mapping to register info.
178   ZoneVector<RegisterInfo*> register_info_table_;
179   int register_info_table_offset_;
180 
181   // Counter for equivalence sets identifiers.
182   int equivalence_id_;
183 
184   BytecodePipelineStage* next_stage_;
185   bool flush_required_;
186   Zone* zone_;
187 
188   DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterOptimizer);
189 };
190 
191 }  // namespace interpreter
192 }  // namespace internal
193 }  // namespace v8
194 
195 #endif  // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
196