LCOV - code coverage report
Current view: top level - src/interpreter - bytecode-register-optimizer.h (source / functions) Hit Total Coverage
Test: app.info Lines: 21 22 95.5 %
Date: 2019-04-18 Functions: 2 4 50.0 %

          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_

Generated by: LCOV version 1.10