LCOV - code coverage report
Current view: top level - src/interpreter - bytecode-register-optimizer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 139 170 81.8 %
Date: 2019-04-18 Functions: 19 32 59.4 %

          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             : #include "src/interpreter/bytecode-register-optimizer.h"
       6             : 
       7             : namespace v8 {
       8             : namespace internal {
       9             : namespace interpreter {
      10             : 
      11             : const uint32_t BytecodeRegisterOptimizer::kInvalidEquivalenceId = kMaxUInt32;
      12             : 
      13             : // A class for tracking the state of a register. This class tracks
      14             : // which equivalence set a register is a member of and also whether a
      15             : // register is materialized in the bytecode stream.
      16             : class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
      17             :  public:
      18             :   RegisterInfo(Register reg, uint32_t equivalence_id, bool materialized,
      19             :                bool allocated)
      20             :       : register_(reg),
      21             :         equivalence_id_(equivalence_id),
      22             :         materialized_(materialized),
      23             :         allocated_(allocated),
      24             :         needs_flush_(false),
      25             :         next_(this),
      26    26596362 :         prev_(this) {}
      27             : 
      28             :   void AddToEquivalenceSetOf(RegisterInfo* info);
      29             :   void MoveToNewEquivalenceSet(uint32_t equivalence_id, bool materialized);
      30             :   bool IsOnlyMemberOfEquivalenceSet() const;
      31             :   bool IsOnlyMaterializedMemberOfEquivalenceSet() const;
      32             :   bool IsInSameEquivalenceSet(RegisterInfo* info) const;
      33             : 
      34             :   // Get a member of the register's equivalence set that is allocated.
      35             :   // Returns itself if allocated, and nullptr if there is no unallocated
      36             :   // equivalent register.
      37             :   RegisterInfo* GetAllocatedEquivalent();
      38             : 
      39             :   // Get a member of this register's equivalence set that is
      40             :   // materialized. The materialized equivalent will be this register
      41             :   // if it is materialized. Returns nullptr if no materialized
      42             :   // equivalent exists.
      43             :   RegisterInfo* GetMaterializedEquivalent();
      44             : 
      45             :   // Get a member of this register's equivalence set that is
      46             :   // materialized and not register |reg|. The materialized equivalent
      47             :   // will be this register if it is materialized. Returns nullptr if
      48             :   // no materialized equivalent exists.
      49             :   RegisterInfo* GetMaterializedEquivalentOtherThan(Register reg);
      50             : 
      51             :   // Get a member of this register's equivalence set that is intended
      52             :   // to be materialized in place of this register (which is currently
      53             :   // materialized). The best candidate is deemed to be the register
      54             :   // with the lowest index as this permits temporary registers to be
      55             :   // removed from the bytecode stream. Returns nullptr if no candidate
      56             :   // exists.
      57             :   RegisterInfo* GetEquivalentToMaterialize();
      58             : 
      59             :   // Marks all temporary registers of the equivalence set as unmaterialized.
      60             :   void MarkTemporariesAsUnmaterialized(Register temporary_base);
      61             : 
      62             :   // Get an equivalent register. Returns this if none exists.
      63             :   RegisterInfo* GetEquivalent();
      64             : 
      65             :   Register register_value() const { return register_; }
      66             :   bool materialized() const { return materialized_; }
      67    63936518 :   void set_materialized(bool materialized) { materialized_ = materialized; }
      68             :   bool allocated() const { return allocated_; }
      69    47527068 :   void set_allocated(bool allocated) { allocated_ = allocated; }
      70             :   void set_equivalence_id(uint32_t equivalence_id) {
      71    32354732 :     equivalence_id_ = equivalence_id;
      72             :   }
      73             :   uint32_t equivalence_id() const { return equivalence_id_; }
      74             :   // Indicates if a register should be processed when calling Flush().
      75             :   bool needs_flush() const { return needs_flush_; }
      76    31895605 :   void set_needs_flush(bool needs_flush) { needs_flush_ = needs_flush; }
      77             : 
      78             :  private:
      79             :   Register register_;
      80             :   uint32_t equivalence_id_;
      81             :   bool materialized_;
      82             :   bool allocated_;
      83             :   bool needs_flush_;
      84             : 
      85             :   // Equivalence set pointers.
      86             :   RegisterInfo* next_;
      87             :   RegisterInfo* prev_;
      88             : 
      89             :   DISALLOW_COPY_AND_ASSIGN(RegisterInfo);
      90             : };
      91             : 
      92           0 : void BytecodeRegisterOptimizer::RegisterInfo::AddToEquivalenceSetOf(
      93             :     RegisterInfo* info) {
      94             :   DCHECK_NE(kInvalidEquivalenceId, info->equivalence_id());
      95             :   // Fix old list
      96    32354732 :   next_->prev_ = prev_;
      97    32354732 :   prev_->next_ = next_;
      98             :   // Add to new list.
      99    32354732 :   next_ = info->next_;
     100    32354732 :   prev_ = info;
     101    32354732 :   prev_->next_ = this;
     102    32354732 :   next_->prev_ = this;
     103             :   set_equivalence_id(info->equivalence_id());
     104             :   set_materialized(false);
     105           0 : }
     106             : 
     107           0 : void BytecodeRegisterOptimizer::RegisterInfo::MoveToNewEquivalenceSet(
     108             :     uint32_t equivalence_id, bool materialized) {
     109    47654521 :   next_->prev_ = prev_;
     110    47654521 :   prev_->next_ = next_;
     111    47654521 :   next_ = prev_ = this;
     112    47654521 :   equivalence_id_ = equivalence_id;
     113    47654521 :   materialized_ = materialized;
     114           0 : }
     115             : 
     116           0 : bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyMemberOfEquivalenceSet()
     117             :     const {
     118           0 :   return this->next_ == this;
     119             : }
     120             : 
     121           0 : bool BytecodeRegisterOptimizer::RegisterInfo::
     122             :     IsOnlyMaterializedMemberOfEquivalenceSet() const {
     123             :   DCHECK(materialized());
     124             : 
     125           0 :   const RegisterInfo* visitor = this->next_;
     126           0 :   while (visitor != this) {
     127           0 :     if (visitor->materialized()) {
     128             :       return false;
     129             :     }
     130           0 :     visitor = visitor->next_;
     131             :   }
     132             :   return true;
     133             : }
     134             : 
     135           0 : bool BytecodeRegisterOptimizer::RegisterInfo::IsInSameEquivalenceSet(
     136             :     RegisterInfo* info) const {
     137           0 :   return equivalence_id() == info->equivalence_id();
     138             : }
     139             : 
     140             : BytecodeRegisterOptimizer::RegisterInfo*
     141           0 : BytecodeRegisterOptimizer::RegisterInfo::GetAllocatedEquivalent() {
     142             :   RegisterInfo* visitor = this;
     143             :   do {
     144           0 :     if (visitor->allocated()) {
     145             :       return visitor;
     146             :     }
     147           0 :     visitor = visitor->next_;
     148           0 :   } while (visitor != this);
     149             : 
     150             :   return nullptr;
     151             : }
     152             : 
     153             : BytecodeRegisterOptimizer::RegisterInfo*
     154           0 : BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() {
     155             :   RegisterInfo* visitor = this;
     156             :   do {
     157    17993618 :     if (visitor->materialized()) {
     158             :       return visitor;
     159             :     }
     160     9361230 :     visitor = visitor->next_;
     161     9361230 :   } while (visitor != this);
     162             : 
     163             :   return nullptr;
     164             : }
     165             : 
     166             : BytecodeRegisterOptimizer::RegisterInfo*
     167           0 : BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalentOtherThan(
     168             :     Register reg) {
     169             :   RegisterInfo* visitor = this;
     170             :   do {
     171     9374048 :     if (visitor->materialized() && visitor->register_value() != reg) {
     172             :       return visitor;
     173             :     }
     174     5013493 :     visitor = visitor->next_;
     175     5013493 :   } while (visitor != this);
     176             : 
     177             :   return nullptr;
     178             : }
     179             : 
     180             : BytecodeRegisterOptimizer::RegisterInfo*
     181    70412372 : BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() {
     182             :   DCHECK(this->materialized());
     183    70412372 :   RegisterInfo* visitor = this->next_;
     184             :   RegisterInfo* best_info = nullptr;
     185   112955830 :   while (visitor != this) {
     186    26095499 :     if (visitor->materialized()) {
     187             :       return nullptr;
     188             :     }
     189    42543458 :     if (visitor->allocated() &&
     190      163895 :         (best_info == nullptr ||
     191             :          visitor->register_value() < best_info->register_value())) {
     192             :       best_info = visitor;
     193             :     }
     194    21271729 :     visitor = visitor->next_;
     195             :   }
     196             :   return best_info;
     197             : }
     198             : 
     199           0 : void BytecodeRegisterOptimizer::RegisterInfo::MarkTemporariesAsUnmaterialized(
     200             :     Register temporary_base) {
     201             :   DCHECK(this->register_value() < temporary_base);
     202             :   DCHECK(this->materialized());
     203     5779403 :   RegisterInfo* visitor = this->next_;
     204    14690610 :   while (visitor != this) {
     205     8911207 :     if (visitor->register_value() >= temporary_base) {
     206             :       visitor->set_materialized(false);
     207             :     }
     208     8911207 :     visitor = visitor->next_;
     209             :   }
     210           0 : }
     211             : 
     212             : BytecodeRegisterOptimizer::RegisterInfo*
     213           0 : BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() {
     214    17465822 :   return next_;
     215             : }
     216             : 
     217     2138304 : BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
     218             :     Zone* zone, BytecodeRegisterAllocator* register_allocator,
     219             :     int fixed_registers_count, int parameter_count,
     220             :     BytecodeWriter* bytecode_writer)
     221             :     : accumulator_(Register::virtual_accumulator()),
     222             :       temporary_base_(fixed_registers_count),
     223     2138306 :       max_register_index_(fixed_registers_count - 1),
     224             :       register_info_table_(zone),
     225             :       registers_needing_flushed_(zone),
     226             :       equivalence_id_(0),
     227             :       bytecode_writer_(bytecode_writer),
     228             :       flush_required_(false),
     229     6414931 :       zone_(zone) {
     230     2138321 :   register_allocator->set_observer(this);
     231             : 
     232             :   // Calculate offset so register index values can be mapped into
     233             :   // a vector of register metadata.
     234             :   // There is at least one parameter, which is the JS receiver.
     235             :   DCHECK_NE(parameter_count, 0);
     236             :   register_info_table_offset_ =
     237     4276642 :       -Register::FromParameterIndex(0, parameter_count).index();
     238             : 
     239             :   // Initialize register map for parameters, locals, and the
     240             :   // accumulator.
     241     4276642 :   register_info_table_.resize(register_info_table_offset_ +
     242     2138321 :                               static_cast<size_t>(temporary_base_.index()));
     243    41008348 :   for (size_t i = 0; i < register_info_table_.size(); ++i) {
     244             :     register_info_table_[i] = new (zone) RegisterInfo(
     245    19434995 :         RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true, true);
     246             :     DCHECK_EQ(register_info_table_[i]->register_value().index(),
     247             :               RegisterFromRegisterInfoTableIndex(i).index());
     248             :   }
     249     2138339 :   accumulator_info_ = GetRegisterInfo(accumulator_);
     250             :   DCHECK(accumulator_info_->register_value() == accumulator_);
     251     2138339 : }
     252             : 
     253           0 : void BytecodeRegisterOptimizer::PushToRegistersNeedingFlush(RegisterInfo* reg) {
     254    32354788 :   if (!reg->needs_flush()) {
     255             :     reg->set_needs_flush(true);
     256    14412686 :     registers_needing_flushed_.push_back(reg);
     257             :   }
     258           0 : }
     259             : 
     260           0 : bool BytecodeRegisterOptimizer::EnsureAllRegistersAreFlushed() const {
     261           0 :   for (RegisterInfo* reg_info : register_info_table_) {
     262           0 :     if (reg_info->needs_flush()) {
     263             :       return false;
     264           0 :     } else if (!reg_info->IsOnlyMemberOfEquivalenceSet()) {
     265             :       return false;
     266           0 :     } else if (reg_info->allocated() && !reg_info->materialized()) {
     267             :       return false;
     268             :     }
     269             :   }
     270             :   return true;
     271             : }
     272             : 
     273     6577446 : void BytecodeRegisterOptimizer::Flush() {
     274     6577446 :   if (!flush_required_) {
     275             :     return;
     276             :   }
     277             : 
     278             :   // Materialize all live registers and break equivalences.
     279    18458453 :   for (RegisterInfo* reg_info : registers_needing_flushed_) {
     280    14278505 :     if (!reg_info->needs_flush()) continue;
     281             :     reg_info->set_needs_flush(false);
     282             : 
     283             :     RegisterInfo* materialized = reg_info->materialized()
     284             :                                      ? reg_info
     285    13500688 :                                      : reg_info->GetMaterializedEquivalent();
     286             : 
     287    13500688 :     if (materialized != nullptr) {
     288             :       // Walk equivalents of materialized registers, materializing
     289             :       // each equivalent register as necessary and placing in their
     290             :       // own equivalence set.
     291             :       RegisterInfo* equivalent;
     292    17465822 :       while ((equivalent = materialized->GetEquivalent()) != materialized) {
     293     3982207 :         if (equivalent->allocated() && !equivalent->materialized()) {
     294      645643 :           OutputRegisterTransfer(materialized, equivalent);
     295             :         }
     296             :         equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
     297             :         equivalent->set_needs_flush(false);
     298             :       }
     299             :     } else {
     300             :       // Equivalernce class containing only unallocated registers.
     301             :       DCHECK_NULL(reg_info->GetAllocatedEquivalent());
     302             :       reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), false);
     303             :     }
     304             :   }
     305             : 
     306     4179948 :   registers_needing_flushed_.clear();
     307             :   DCHECK(EnsureAllRegistersAreFlushed());
     308             : 
     309     4179945 :   flush_required_ = false;
     310             : }
     311             : 
     312    25571451 : void BytecodeRegisterOptimizer::OutputRegisterTransfer(
     313             :     RegisterInfo* input_info, RegisterInfo* output_info) {
     314             :   Register input = input_info->register_value();
     315             :   Register output = output_info->register_value();
     316             :   DCHECK_NE(input.index(), output.index());
     317             : 
     318    25571451 :   if (input == accumulator_) {
     319    20374927 :     bytecode_writer_->EmitStar(output);
     320     5196524 :   } else if (output == accumulator_) {
     321     3816891 :     bytecode_writer_->EmitLdar(input);
     322             :   } else {
     323     1379633 :     bytecode_writer_->EmitMov(input, output);
     324             :   }
     325    25570861 :   if (output != accumulator_) {
     326    43507904 :     max_register_index_ = std::max(max_register_index_, output.index());
     327             :   }
     328             :   output_info->set_materialized(true);
     329    25570861 : }
     330             : 
     331    70412449 : void BytecodeRegisterOptimizer::CreateMaterializedEquivalent(
     332             :     RegisterInfo* info) {
     333             :   DCHECK(info->materialized());
     334    70412449 :   RegisterInfo* unmaterialized = info->GetEquivalentToMaterialize();
     335    70412686 :   if (unmaterialized) {
     336    17930474 :     OutputRegisterTransfer(info, unmaterialized);
     337             :   }
     338    70412274 : }
     339             : 
     340             : BytecodeRegisterOptimizer::RegisterInfo*
     341           0 : BytecodeRegisterOptimizer::GetMaterializedEquivalent(RegisterInfo* info) {
     342           0 :   return info->materialized() ? info : info->GetMaterializedEquivalent();
     343             : }
     344             : 
     345             : BytecodeRegisterOptimizer::RegisterInfo*
     346     4365091 : BytecodeRegisterOptimizer::GetMaterializedEquivalentNotAccumulator(
     347             :     RegisterInfo* info) {
     348     4365091 :   if (info->materialized()) {
     349             :     return info;
     350             :   }
     351             : 
     352             :   RegisterInfo* result = info->GetMaterializedEquivalentOtherThan(accumulator_);
     353     4365096 :   if (result == nullptr) {
     354        4549 :     Materialize(info);
     355             :     result = info;
     356             :   }
     357             :   DCHECK(result->register_value() != accumulator_);
     358             :   return result;
     359             : }
     360             : 
     361    25109885 : void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) {
     362    25109885 :   if (!info->materialized()) {
     363             :     RegisterInfo* materialized = info->GetMaterializedEquivalent();
     364             :     DCHECK_NOT_NULL(materialized);
     365     4460149 :     OutputRegisterTransfer(materialized, info);
     366             :   }
     367    25109909 : }
     368             : 
     369    32354788 : void BytecodeRegisterOptimizer::AddToEquivalenceSet(
     370             :     RegisterInfo* set_member, RegisterInfo* non_set_member) {
     371             :   // Equivalence class is now of size >= 2, so we make sure it will be flushed.
     372             :   PushToRegistersNeedingFlush(non_set_member);
     373             :   non_set_member->AddToEquivalenceSetOf(set_member);
     374             :   // Flushing is only required when two or more registers are placed
     375             :   // in the same equivalence set.
     376    32354732 :   flush_required_ = true;
     377    32354732 : }
     378             : 
     379    34039237 : void BytecodeRegisterOptimizer::RegisterTransfer(RegisterInfo* input_info,
     380             :                                                  RegisterInfo* output_info) {
     381             :   bool output_is_observable =
     382             :       RegisterIsObservable(output_info->register_value());
     383             :   bool in_same_equivalence_set =
     384             :       output_info->IsInSameEquivalenceSet(input_info);
     385    68078474 :   if (in_same_equivalence_set &&
     386        1718 :       (!output_is_observable || output_info->materialized())) {
     387             :     return;  // Nothing more to do.
     388             :   }
     389             : 
     390             :   // Materialize an alternate in the equivalence set that
     391             :   // |output_info| is leaving.
     392    32354471 :   if (output_info->materialized()) {
     393    31834520 :     CreateMaterializedEquivalent(output_info);
     394             :   }
     395             : 
     396             :   // Add |output_info| to new equivalence set.
     397    32355492 :   if (!in_same_equivalence_set) {
     398    32354818 :     AddToEquivalenceSet(input_info, output_info);
     399             :   }
     400             : 
     401    32355109 :   if (output_is_observable) {
     402             :     // Force store to be emitted when register is observable.
     403             :     output_info->set_materialized(false);
     404             :     RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent();
     405     2535295 :     OutputRegisterTransfer(materialized_info, output_info);
     406             :   }
     407             : 
     408             :   bool input_is_observable = RegisterIsObservable(input_info->register_value());
     409    32355124 :   if (input_is_observable) {
     410             :     // If input is observable by the debugger, mark all other temporaries
     411             :     // registers as unmaterialized so that this register is used in preference.
     412             :     input_info->MarkTemporariesAsUnmaterialized(temporary_base_);
     413             :   }
     414             : }
     415             : 
     416    40453984 : void BytecodeRegisterOptimizer::PrepareOutputRegister(Register reg) {
     417             :   RegisterInfo* reg_info = GetRegisterInfo(reg);
     418    40453984 :   if (reg_info->materialized()) {
     419    38586621 :     CreateMaterializedEquivalent(reg_info);
     420             :   }
     421             :   reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
     422             :   max_register_index_ =
     423    80907416 :       std::max(max_register_index_, reg_info->register_value().index());
     424    40453708 : }
     425             : 
     426       33265 : void BytecodeRegisterOptimizer::PrepareOutputRegisterList(
     427             :     RegisterList reg_list) {
     428             :   int start_index = reg_list.first_register().index();
     429      322573 :   for (int i = 0; i < reg_list.register_count(); ++i) {
     430      144654 :     Register current(start_index + i);
     431      144654 :     PrepareOutputRegister(current);
     432             :   }
     433       33265 : }
     434             : 
     435    16764641 : Register BytecodeRegisterOptimizer::GetInputRegister(Register reg) {
     436             :   RegisterInfo* reg_info = GetRegisterInfo(reg);
     437    16764641 :   if (reg_info->materialized()) {
     438    12399553 :     return reg;
     439             :   } else {
     440             :     RegisterInfo* equivalent_info =
     441     4365088 :         GetMaterializedEquivalentNotAccumulator(reg_info);
     442             :     return equivalent_info->register_value();
     443             :   }
     444             : }
     445             : 
     446     2892865 : RegisterList BytecodeRegisterOptimizer::GetInputRegisterList(
     447             :     RegisterList reg_list) {
     448     2892865 :   if (reg_list.register_count() == 1) {
     449             :     // If there is only a single register, treat it as a normal input register.
     450      703655 :     Register reg(GetInputRegister(reg_list.first_register()));
     451      703660 :     return RegisterList(reg);
     452             :   } else {
     453             :     int start_index = reg_list.first_register().index();
     454    17888232 :     for (int i = 0; i < reg_list.register_count(); ++i) {
     455     7849498 :       Register current(start_index + i);
     456             :       RegisterInfo* input_info = GetRegisterInfo(current);
     457     7849498 :       Materialize(input_info);
     458             :     }
     459     2189223 :     return reg_list;
     460             :   }
     461             : }
     462             : 
     463     6704105 : void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) {
     464             :   DCHECK(RegisterIsTemporary(reg));
     465             :   size_t index = GetRegisterInfoTableIndex(reg);
     466     6704105 :   if (index >= register_info_table_.size()) {
     467     6347651 :     size_t new_size = index + 1;
     468             :     size_t old_size = register_info_table_.size();
     469     6347651 :     register_info_table_.resize(new_size);
     470    20670432 :     for (size_t i = old_size; i < new_size; ++i) {
     471             :       register_info_table_[i] =
     472             :           new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(i),
     473     7161367 :                                     NextEquivalenceId(), true, false);
     474             :     }
     475             :   }
     476     6704115 : }
     477             : 
     478    23764462 : void BytecodeRegisterOptimizer::AllocateRegister(RegisterInfo* info) {
     479             :   info->set_allocated(true);
     480    23764462 :   if (!info->materialized()) {
     481             :     info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
     482             :   }
     483    23764462 : }
     484             : 
     485    21830430 : void BytecodeRegisterOptimizer::RegisterAllocateEvent(Register reg) {
     486    21830430 :   AllocateRegister(GetOrCreateRegisterInfo(reg));
     487    21830389 : }
     488             : 
     489      699033 : void BytecodeRegisterOptimizer::RegisterListAllocateEvent(
     490             :     RegisterList reg_list) {
     491      699033 :   if (reg_list.register_count() != 0) {
     492             :     int first_index = reg_list.first_register().index();
     493     1398078 :     GrowRegisterMap(Register(first_index + reg_list.register_count() - 1));
     494     4567818 :     for (int i = 0; i < reg_list.register_count(); i++) {
     495     3868810 :       AllocateRegister(GetRegisterInfo(Register(first_index + i)));
     496             :     }
     497             :   }
     498      699023 : }
     499             : 
     500    81385987 : void BytecodeRegisterOptimizer::RegisterListFreeEvent(RegisterList reg_list) {
     501             :   int first_index = reg_list.first_register().index();
     502   128911199 :   for (int i = 0; i < reg_list.register_count(); i++) {
     503    23762606 :     GetRegisterInfo(Register(first_index + i))->set_allocated(false);
     504             :   }
     505    81385987 : }
     506             : 
     507             : }  // namespace interpreter
     508             : }  // namespace internal
     509      122036 : }  // namespace v8

Generated by: LCOV version 1.10