Home | History | Annotate | Download | only in interpreter
      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