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 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