LCOV - code coverage report
Current view: top level - src/interpreter - bytecode-register-optimizer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 142 164 86.6 %
Date: 2017-04-26 Functions: 16 27 59.3 %

          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             :         next_(this),
      25    29585244 :         prev_(this) {}
      26             : 
      27             :   void AddToEquivalenceSetOf(RegisterInfo* info);
      28             :   void MoveToNewEquivalenceSet(uint32_t equivalence_id, bool materialized);
      29             :   bool IsOnlyMemberOfEquivalenceSet() const;
      30             :   bool IsOnlyMaterializedMemberOfEquivalenceSet() const;
      31             :   bool IsInSameEquivalenceSet(RegisterInfo* info) const;
      32             : 
      33             :   // Get a member of this register's equivalence set that is
      34             :   // materialized. The materialized equivalent will be this register
      35             :   // if it is materialized. Returns nullptr if no materialized
      36             :   // equivalent exists.
      37             :   RegisterInfo* GetMaterializedEquivalent();
      38             : 
      39             :   // Get a member of this register's equivalence set that is
      40             :   // materialized and not register |reg|. The materialized equivalent
      41             :   // will be this register if it is materialized. Returns nullptr if
      42             :   // no materialized equivalent exists.
      43             :   RegisterInfo* GetMaterializedEquivalentOtherThan(Register reg);
      44             : 
      45             :   // Get a member of this register's equivalence set that is intended
      46             :   // to be materialized in place of this register (which is currently
      47             :   // materialized). The best candidate is deemed to be the register
      48             :   // with the lowest index as this permits temporary registers to be
      49             :   // removed from the bytecode stream. Returns nullptr if no candidate
      50             :   // exists.
      51             :   RegisterInfo* GetEquivalentToMaterialize();
      52             : 
      53             :   // Marks all temporary registers of the equivalence set as unmaterialized.
      54             :   void MarkTemporariesAsUnmaterialized(Register temporary_base);
      55             : 
      56             :   // Get an equivalent register. Returns this if none exists.
      57             :   RegisterInfo* GetEquivalent();
      58             : 
      59             :   Register register_value() const { return register_; }
      60             :   bool materialized() const { return materialized_; }
      61    60962501 :   void set_materialized(bool materialized) { materialized_ = materialized; }
      62             :   bool allocated() const { return allocated_; }
      63    42112371 :   void set_allocated(bool allocated) { allocated_ = allocated; }
      64             :   void set_equivalence_id(uint32_t equivalence_id) {
      65    31904317 :     equivalence_id_ = equivalence_id;
      66             :   }
      67             :   uint32_t equivalence_id() const { return equivalence_id_; }
      68             : 
      69             :  private:
      70             :   Register register_;
      71             :   uint32_t equivalence_id_;
      72             :   bool materialized_;
      73             :   bool allocated_;
      74             : 
      75             :   // Equivalence set pointers.
      76             :   RegisterInfo* next_;
      77             :   RegisterInfo* prev_;
      78             : 
      79             :   DISALLOW_COPY_AND_ASSIGN(RegisterInfo);
      80             : };
      81             : 
      82           0 : void BytecodeRegisterOptimizer::RegisterInfo::AddToEquivalenceSetOf(
      83    31904317 :     RegisterInfo* info) {
      84             :   DCHECK_NE(kInvalidEquivalenceId, info->equivalence_id());
      85             :   // Fix old list
      86    31904317 :   next_->prev_ = prev_;
      87    31904317 :   prev_->next_ = next_;
      88             :   // Add to new list.
      89    31904317 :   next_ = info->next_;
      90    31904317 :   prev_ = info;
      91    31904317 :   prev_->next_ = this;
      92    31904317 :   next_->prev_ = this;
      93             :   set_equivalence_id(info->equivalence_id());
      94             :   set_materialized(false);
      95           0 : }
      96             : 
      97           0 : void BytecodeRegisterOptimizer::RegisterInfo::MoveToNewEquivalenceSet(
      98             :     uint32_t equivalence_id, bool materialized) {
      99    39554291 :   next_->prev_ = prev_;
     100    39554291 :   prev_->next_ = next_;
     101    39554291 :   next_ = prev_ = this;
     102    39554291 :   equivalence_id_ = equivalence_id;
     103    39554291 :   materialized_ = materialized;
     104           0 : }
     105             : 
     106           0 : bool BytecodeRegisterOptimizer::RegisterInfo::IsOnlyMemberOfEquivalenceSet()
     107             :     const {
     108           0 :   return this->next_ == this;
     109             : }
     110             : 
     111           0 : bool BytecodeRegisterOptimizer::RegisterInfo::
     112             :     IsOnlyMaterializedMemberOfEquivalenceSet() const {
     113             :   DCHECK(materialized());
     114             : 
     115           0 :   const RegisterInfo* visitor = this->next_;
     116           0 :   while (visitor != this) {
     117           0 :     if (visitor->materialized()) {
     118             :       return false;
     119             :     }
     120           0 :     visitor = visitor->next_;
     121             :   }
     122             :   return true;
     123             : }
     124             : 
     125           0 : bool BytecodeRegisterOptimizer::RegisterInfo::IsInSameEquivalenceSet(
     126    34246841 :     RegisterInfo* info) const {
     127           0 :   return equivalence_id() == info->equivalence_id();
     128             : }
     129             : 
     130             : BytecodeRegisterOptimizer::RegisterInfo*
     131           0 : BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalent() {
     132    11806666 :   RegisterInfo* visitor = this;
     133     4433055 :   do {
     134    11806666 :     if (visitor->materialized()) {
     135             :       return visitor;
     136             :     }
     137     4433055 :     visitor = visitor->next_;
     138             :   } while (visitor != this);
     139             : 
     140             :   return nullptr;
     141             : }
     142             : 
     143             : BytecodeRegisterOptimizer::RegisterInfo*
     144           0 : BytecodeRegisterOptimizer::RegisterInfo::GetMaterializedEquivalentOtherThan(
     145             :     Register reg) {
     146     8207717 :   RegisterInfo* visitor = this;
     147     4160833 :   do {
     148     8207717 :     if (visitor->materialized() && visitor->register_value() != reg) {
     149             :       return visitor;
     150             :     }
     151     4160833 :     visitor = visitor->next_;
     152             :   } while (visitor != this);
     153             : 
     154             :   return nullptr;
     155             : }
     156             : 
     157             : BytecodeRegisterOptimizer::RegisterInfo*
     158    54338260 : BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() {
     159             :   DCHECK(this->materialized());
     160    94060026 :   RegisterInfo* visitor = this->next_;
     161             :   RegisterInfo* best_info = nullptr;
     162   125638587 :   while (visitor != this) {
     163    22759699 :     if (visitor->materialized()) {
     164             :       return nullptr;
     165             :     }
     166    33924134 :     if (visitor->allocated() &&
     167      164605 :         (best_info == nullptr ||
     168             :          visitor->register_value() < best_info->register_value())) {
     169             :       best_info = visitor;
     170             :     }
     171    16962067 :     visitor = visitor->next_;
     172             :   }
     173             :   return best_info;
     174             : }
     175             : 
     176           0 : void BytecodeRegisterOptimizer::RegisterInfo::MarkTemporariesAsUnmaterialized(
     177             :     Register temporary_base) {
     178             :   DCHECK(this->register_value() < temporary_base);
     179             :   DCHECK(this->materialized());
     180     8017778 :   RegisterInfo* visitor = this->next_;
     181    16876164 :   while (visitor != this) {
     182     8858386 :     if (visitor->register_value() >= temporary_base) {
     183             :       visitor->set_materialized(false);
     184             :     }
     185     8858386 :     visitor = visitor->next_;
     186             :   }
     187           0 : }
     188             : 
     189             : BytecodeRegisterOptimizer::RegisterInfo*
     190           0 : BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() {
     191  1603972505 :   return next_;
     192             : }
     193             : 
     194     2104165 : BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
     195             :     Zone* zone, BytecodeRegisterAllocator* register_allocator,
     196             :     int fixed_registers_count, int parameter_count,
     197    22140082 :     BytecodeWriter* bytecode_writer)
     198             :     : accumulator_(Register::virtual_accumulator()),
     199             :       temporary_base_(fixed_registers_count),
     200     2104165 :       max_register_index_(fixed_registers_count - 1),
     201             :       register_info_table_(zone),
     202             :       equivalence_id_(0),
     203             :       bytecode_writer_(bytecode_writer),
     204             :       flush_required_(false),
     205     6312495 :       zone_(zone) {
     206     2104165 :   register_allocator->set_observer(this);
     207             : 
     208             :   // Calculate offset so register index values can be mapped into
     209             :   // a vector of register metadata.
     210     2104165 :   if (parameter_count != 0) {
     211             :     register_info_table_offset_ =
     212     4177929 :         -Register::FromParameterIndex(0, parameter_count).index();
     213             :   } else {
     214             :     // TODO(oth): This path shouldn't be necessary in bytecode generated
     215             :     // from Javascript, but a set of tests do not include the JS receiver.
     216       15200 :     register_info_table_offset_ = -accumulator_.index();
     217             :   }
     218             : 
     219             :   // Initialize register map for parameters, locals, and the
     220             :   // accumulator.
     221             :   register_info_table_.resize(register_info_table_offset_ +
     222    50592659 :                               static_cast<size_t>(temporary_base_.index()));
     223    48488512 :   for (size_t i = 0; i < register_info_table_.size(); ++i) {
     224             :     register_info_table_[i] = new (zone) RegisterInfo(
     225    44280157 :         RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true, true);
     226             :     DCHECK_EQ(register_info_table_[i]->register_value().index(),
     227             :               RegisterFromRegisterInfoTableIndex(i).index());
     228             :   }
     229     2104174 :   accumulator_info_ = GetRegisterInfo(accumulator_);
     230             :   DCHECK(accumulator_info_->register_value() == accumulator_);
     231     2104174 : }
     232             : 
     233     9963180 : void BytecodeRegisterOptimizer::Flush() {
     234     9963180 :   if (!flush_required_) {
     235     9963173 :     return;
     236             :   }
     237             : 
     238             :   // Materialize all live registers and break equivalences.
     239  1604042611 :   size_t count = register_info_table_.size();
     240  1604042604 :   for (size_t i = 0; i < count; ++i) {
     241  1598354857 :     RegisterInfo* reg_info = register_info_table_[i];
     242  1598354857 :     if (reg_info->materialized()) {
     243             :       // Walk equivalents of materialized registers, materializing
     244             :       // each equivalent register as necessary and placing in their
     245             :       // own equivalence set.
     246     8945912 :       RegisterInfo* equivalent;
     247  1603972505 :       while ((equivalent = reg_info->GetEquivalent()) != reg_info) {
     248     8945912 :         if (equivalent->allocated() && !equivalent->materialized()) {
     249      693279 :           OutputRegisterTransfer(reg_info, equivalent);
     250             :         }
     251     6042198 :         equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
     252             :       }
     253             :     }
     254             :   }
     255             : 
     256     5687747 :   flush_required_ = false;
     257             : }
     258             : 
     259    24471645 : void BytecodeRegisterOptimizer::OutputRegisterTransfer(
     260             :     RegisterInfo* input_info, RegisterInfo* output_info) {
     261             :   Register input = input_info->register_value();
     262             :   Register output = output_info->register_value();
     263             :   DCHECK_NE(input.index(), output.index());
     264             : 
     265    24471645 :   if (input == accumulator_) {
     266    19578329 :     bytecode_writer_->EmitStar(output);
     267     4893316 :   } else if (output == accumulator_) {
     268     2726163 :     bytecode_writer_->EmitLdar(input);
     269             :   } else {
     270     2167153 :     bytecode_writer_->EmitMov(input, output);
     271             :   }
     272    24471640 :   if (output != accumulator_) {
     273    43490952 :     max_register_index_ = std::max(max_register_index_, output.index());
     274             :   }
     275             :   output_info->set_materialized(true);
     276    24471640 : }
     277             : 
     278    54338258 : void BytecodeRegisterOptimizer::CreateMaterializedEquivalent(
     279             :     RegisterInfo* info) {
     280             :   DCHECK(info->materialized());
     281    54338258 :   RegisterInfo* unmaterialized = info->GetEquivalentToMaterialize();
     282    54338276 :   if (unmaterialized) {
     283    16404762 :     OutputRegisterTransfer(info, unmaterialized);
     284             :   }
     285    54338278 : }
     286             : 
     287             : BytecodeRegisterOptimizer::RegisterInfo*
     288           0 : BytecodeRegisterOptimizer::GetMaterializedEquivalent(RegisterInfo* info) {
     289           0 :   return info->materialized() ? info : info->GetMaterializedEquivalent();
     290             : }
     291             : 
     292             : BytecodeRegisterOptimizer::RegisterInfo*
     293     4049638 : BytecodeRegisterOptimizer::GetMaterializedEquivalentNotAccumulator(
     294     4049638 :     RegisterInfo* info) {
     295     4049638 :   if (info->materialized()) {
     296             :     return info;
     297             :   }
     298             : 
     299             :   RegisterInfo* result = info->GetMaterializedEquivalentOtherThan(accumulator_);
     300     4049638 :   if (result == nullptr) {
     301        2754 :     Materialize(info);
     302             :     result = info;
     303             :   }
     304             :   DCHECK(result->register_value() != accumulator_);
     305     4049638 :   return result;
     306             : }
     307             : 
     308    21343537 : void BytecodeRegisterOptimizer::Materialize(RegisterInfo* info) {
     309    21343537 :   if (!info->materialized()) {
     310             :     RegisterInfo* materialized = info->GetMaterializedEquivalent();
     311     3820335 :     OutputRegisterTransfer(materialized, info);
     312             :   }
     313    21343538 : }
     314             : 
     315           0 : void BytecodeRegisterOptimizer::AddToEquivalenceSet(
     316             :     RegisterInfo* set_member, RegisterInfo* non_set_member) {
     317             :   non_set_member->AddToEquivalenceSetOf(set_member);
     318             :   // Flushing is only required when two or more registers are placed
     319             :   // in the same equivalence set.
     320    31904317 :   flush_required_ = true;
     321           0 : }
     322             : 
     323    34246744 : void BytecodeRegisterOptimizer::RegisterTransfer(RegisterInfo* input_info,
     324    34246744 :                                                  RegisterInfo* output_info) {
     325             :   // Materialize an alternate in the equivalence set that
     326             :   // |output_info| is leaving.
     327    34246744 :   if (output_info->materialized()) {
     328    24201395 :     CreateMaterializedEquivalent(output_info);
     329             :   }
     330             : 
     331             :   // Add |output_info| to new equivalence set.
     332    34246841 :   if (!output_info->IsInSameEquivalenceSet(input_info)) {
     333             :     AddToEquivalenceSet(input_info, output_info);
     334             :   }
     335             : 
     336             :   bool output_is_observable =
     337             :       RegisterIsObservable(output_info->register_value());
     338    34246841 :   if (output_is_observable) {
     339             :     // Force store to be emitted when register is observable.
     340             :     output_info->set_materialized(false);
     341             :     RegisterInfo* materialized_info = input_info->GetMaterializedEquivalent();
     342     3553276 :     OutputRegisterTransfer(materialized_info, output_info);
     343             :   }
     344             : 
     345             :   bool input_is_observable = RegisterIsObservable(input_info->register_value());
     346    34246842 :   if (input_is_observable) {
     347             :     // If input is observable by the debugger, mark all other temporaries
     348             :     // registers as unmaterialized so that this register is used in preference.
     349             :     input_info->MarkTemporariesAsUnmaterialized(temporary_base_);
     350             :   }
     351    34246842 : }
     352             : 
     353    33512119 : void BytecodeRegisterOptimizer::PrepareOutputRegister(Register reg) {
     354    33512119 :   RegisterInfo* reg_info = GetRegisterInfo(reg);
     355    33512119 :   if (reg_info->materialized()) {
     356    30137101 :     CreateMaterializedEquivalent(reg_info);
     357             :   }
     358    33512099 :   reg_info->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
     359             :   max_register_index_ =
     360    67024200 :       std::max(max_register_index_, reg_info->register_value().index());
     361    33512100 : }
     362             : 
     363        8536 : void BytecodeRegisterOptimizer::PrepareOutputRegisterList(
     364             :     RegisterList reg_list) {
     365             :   int start_index = reg_list.first_register().index();
     366       31381 :   for (int i = 0; i < reg_list.register_count(); ++i) {
     367       22845 :     Register current(start_index + i);
     368       22845 :     PrepareOutputRegister(current);
     369             :   }
     370        8536 : }
     371             : 
     372    16609728 : Register BytecodeRegisterOptimizer::GetInputRegister(Register reg) {
     373    16609728 :   RegisterInfo* reg_info = GetRegisterInfo(reg);
     374    16609728 :   if (reg_info->materialized()) {
     375    12560090 :     return reg;
     376             :   } else {
     377             :     RegisterInfo* equivalent_info =
     378     4049638 :         GetMaterializedEquivalentNotAccumulator(reg_info);
     379             :     return equivalent_info->register_value();
     380             :   }
     381             : }
     382             : 
     383     2380621 : RegisterList BytecodeRegisterOptimizer::GetInputRegisterList(
     384             :     RegisterList reg_list) {
     385     2380621 :   if (reg_list.register_count() == 1) {
     386             :     // If there is only a single register, treat it as a normal input register.
     387     1093131 :     Register reg(GetInputRegister(reg_list.first_register()));
     388     1093131 :     return RegisterList(reg.index(), 1);
     389             :   } else {
     390             :     int start_index = reg_list.first_register().index();
     391     7949614 :     for (int i = 0; i < reg_list.register_count(); ++i) {
     392     6662120 :       Register current(start_index + i);
     393             :       RegisterInfo* input_info = GetRegisterInfo(current);
     394     6662120 :       Materialize(input_info);
     395             :     }
     396     1287494 :     return reg_list;
     397             :   }
     398             : }
     399             : 
     400    21491103 : void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) {
     401             :   DCHECK(RegisterIsTemporary(reg));
     402             :   size_t index = GetRegisterInfoTableIndex(reg);
     403    20646689 :   if (index >= register_info_table_.size()) {
     404     6514657 :     size_t new_size = index + 1;
     405             :     size_t old_size = register_info_table_.size();
     406     6514657 :     register_info_table_.resize(new_size);
     407    13959834 :     for (size_t i = old_size; i < new_size; ++i) {
     408             :       register_info_table_[i] =
     409             :           new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(i),
     410    14890341 :                                     NextEquivalenceId(), false, false);
     411             :     }
     412             :   }
     413     6600765 : }
     414             : 
     415    19437928 : void BytecodeRegisterOptimizer::RegisterAllocateEvent(Register reg) {
     416    19437928 :   GetOrCreateRegisterInfo(reg)->set_allocated(true);
     417    19437937 : }
     418             : 
     419      413292 : void BytecodeRegisterOptimizer::RegisterListAllocateEvent(
     420             :     RegisterList reg_list) {
     421      413292 :   if (reg_list.register_count() != 0) {
     422             :     int first_index = reg_list.first_register().index();
     423      826584 :     GrowRegisterMap(Register(first_index + reg_list.register_count() - 1));
     424     2033814 :     for (int i = 0; i < reg_list.register_count(); i++) {
     425     1620522 :       GetRegisterInfo(Register(first_index + i))->set_allocated(true);
     426             :     }
     427             :   }
     428      413292 : }
     429             : 
     430    74661012 : void BytecodeRegisterOptimizer::RegisterListFreeEvent(RegisterList reg_list) {
     431             :   int first_index = reg_list.first_register().index();
     432    95714924 :   for (int i = 0; i < reg_list.register_count(); i++) {
     433    21053912 :     GetRegisterInfo(Register(first_index + i))->set_allocated(false);
     434             :   }
     435    74661012 : }
     436             : 
     437             : }  // namespace interpreter
     438             : }  // namespace internal
     439             : }  // namespace v8

Generated by: LCOV version 1.10