LCOV - code coverage report
Current view: top level - src/compiler - bytecode-analysis.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 145 163 89.0 %
Date: 2017-10-20 Functions: 16 18 88.9 %

          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/compiler/bytecode-analysis.h"
       6             : 
       7             : #include "src/interpreter/bytecode-array-iterator.h"
       8             : #include "src/interpreter/bytecode-array-random-iterator.h"
       9             : #include "src/objects-inl.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : namespace compiler {
      14             : 
      15             : using interpreter::Bytecode;
      16             : using interpreter::Bytecodes;
      17             : using interpreter::OperandType;
      18             : 
      19       61601 : BytecodeLoopAssignments::BytecodeLoopAssignments(int parameter_count,
      20             :                                                  int register_count, Zone* zone)
      21             :     : parameter_count_(parameter_count),
      22             :       bit_vector_(new (zone)
      23      123202 :                       BitVector(parameter_count + register_count, zone)) {}
      24             : 
      25      586812 : void BytecodeLoopAssignments::Add(interpreter::Register r) {
      26      586812 :   if (r.is_parameter()) {
      27        3854 :     bit_vector_->Add(r.ToParameterIndex(parameter_count_));
      28             :   } else {
      29      582958 :     bit_vector_->Add(parameter_count_ + r.index());
      30             :   }
      31      586812 : }
      32             : 
      33         685 : void BytecodeLoopAssignments::AddList(interpreter::Register r, uint32_t count) {
      34         685 :   if (r.is_parameter()) {
      35           0 :     for (uint32_t i = 0; i < count; i++) {
      36             :       DCHECK(interpreter::Register(r.index() + i).is_parameter());
      37           0 :       bit_vector_->Add(r.ToParameterIndex(parameter_count_) + i);
      38             :     }
      39             :   } else {
      40        5950 :     for (uint32_t i = 0; i < count; i++) {
      41             :       DCHECK(!interpreter::Register(r.index() + i).is_parameter());
      42       11900 :       bit_vector_->Add(parameter_count_ + r.index() + i);
      43             :     }
      44             :   }
      45         685 : }
      46             : 
      47             : 
      48           0 : void BytecodeLoopAssignments::Union(const BytecodeLoopAssignments& other) {
      49        8505 :   bit_vector_->Union(*other.bit_vector_);
      50           0 : }
      51             : 
      52      348775 : bool BytecodeLoopAssignments::ContainsParameter(int index) const {
      53             :   DCHECK_GE(index, 0);
      54             :   DCHECK_LT(index, parameter_count());
      55      697550 :   return bit_vector_->Contains(index);
      56             : }
      57             : 
      58     2966503 : bool BytecodeLoopAssignments::ContainsLocal(int index) const {
      59             :   DCHECK_GE(index, 0);
      60             :   DCHECK_LT(index, local_count());
      61     5933006 :   return bit_vector_->Contains(parameter_count_ + index);
      62             : }
      63             : 
      64      504916 : BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
      65             :                                    Zone* zone, bool do_liveness_analysis)
      66             :     : bytecode_array_(bytecode_array),
      67             :       do_liveness_analysis_(do_liveness_analysis),
      68             :       zone_(zone),
      69             :       loop_stack_(zone),
      70             :       loop_end_index_queue_(zone),
      71             :       end_to_header_(zone),
      72             :       header_to_info_(zone),
      73             :       osr_entry_point_(-1),
      74     1514754 :       liveness_map_(bytecode_array->length(), zone) {}
      75             : 
      76             : namespace {
      77             : 
      78    18021399 : void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState& in_liveness,
      79             :                       const interpreter::BytecodeArrayAccessor& accessor) {
      80             :   int num_operands = Bytecodes::NumberOfOperands(bytecode);
      81             :   const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
      82             : 
      83    18021399 :   if (Bytecodes::WritesAccumulator(bytecode)) {
      84             :     in_liveness.MarkAccumulatorDead();
      85             :   }
      86    24895410 :   for (int i = 0; i < num_operands; ++i) {
      87    24895426 :     switch (operand_types[i]) {
      88             :       case OperandType::kRegOut: {
      89     5217192 :         interpreter::Register r = accessor.GetRegisterOperand(i);
      90     5217193 :         if (!r.is_parameter()) {
      91             :           in_liveness.MarkRegisterDead(r.index());
      92             :         }
      93             :         break;
      94             :       }
      95             :       case OperandType::kRegOutList: {
      96        5705 :         interpreter::Register r = accessor.GetRegisterOperand(i++);
      97        5705 :         uint32_t reg_count = accessor.GetRegisterCountOperand(i);
      98        5705 :         if (!r.is_parameter()) {
      99       42566 :           for (uint32_t j = 0; j < reg_count; ++j) {
     100             :             DCHECK(!interpreter::Register(r.index() + j).is_parameter());
     101       42566 :             in_liveness.MarkRegisterDead(r.index() + j);
     102             :           }
     103             :         }
     104             :         break;
     105             :       }
     106             :       case OperandType::kRegOutPair: {
     107         397 :         interpreter::Register r = accessor.GetRegisterOperand(i);
     108         397 :         if (!r.is_parameter()) {
     109             :           DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
     110             :           in_liveness.MarkRegisterDead(r.index());
     111         397 :           in_liveness.MarkRegisterDead(r.index() + 1);
     112             :         }
     113             :         break;
     114             :       }
     115             :       case OperandType::kRegOutTriple: {
     116        1964 :         interpreter::Register r = accessor.GetRegisterOperand(i);
     117        1964 :         if (!r.is_parameter()) {
     118             :           DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
     119             :           DCHECK(!interpreter::Register(r.index() + 2).is_parameter());
     120             :           in_liveness.MarkRegisterDead(r.index());
     121        1964 :           in_liveness.MarkRegisterDead(r.index() + 1);
     122        1964 :           in_liveness.MarkRegisterDead(r.index() + 2);
     123             :         }
     124             :         break;
     125             :       }
     126             :       default:
     127             :         DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i]));
     128             :         break;
     129             :     }
     130             :   }
     131             : 
     132    18021386 :   if (Bytecodes::ReadsAccumulator(bytecode)) {
     133     9176042 :     in_liveness.MarkAccumulatorLive();
     134             :   }
     135    24563883 :   for (int i = 0; i < num_operands; ++i) {
     136    24563878 :     switch (operand_types[i]) {
     137             :       case OperandType::kReg: {
     138     6078345 :         interpreter::Register r = accessor.GetRegisterOperand(i);
     139     6078350 :         if (!r.is_parameter()) {
     140             :           in_liveness.MarkRegisterLive(r.index());
     141             :         }
     142             :         break;
     143             :       }
     144             :       case OperandType::kRegPair: {
     145        3716 :         interpreter::Register r = accessor.GetRegisterOperand(i);
     146        3716 :         if (!r.is_parameter()) {
     147             :           DCHECK(!interpreter::Register(r.index() + 1).is_parameter());
     148             :           in_liveness.MarkRegisterLive(r.index());
     149        3716 :           in_liveness.MarkRegisterLive(r.index() + 1);
     150             :         }
     151             :         break;
     152             :       }
     153             :       case OperandType::kRegList: {
     154      337231 :         interpreter::Register r = accessor.GetRegisterOperand(i++);
     155      337231 :         uint32_t reg_count = accessor.GetRegisterCountOperand(i);
     156      337231 :         if (!r.is_parameter()) {
     157     1230562 :           for (uint32_t j = 0; j < reg_count; ++j) {
     158             :             DCHECK(!interpreter::Register(r.index() + j).is_parameter());
     159     1230562 :             in_liveness.MarkRegisterLive(r.index() + j);
     160             :           }
     161             :         }
     162             :         break;
     163             :       }
     164             :       default:
     165             :         DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_types[i]));
     166             :         break;
     167             :     }
     168             :   }
     169    18021396 : }
     170             : 
     171    18077542 : void UpdateOutLiveness(Bytecode bytecode, BytecodeLivenessState& out_liveness,
     172             :                        BytecodeLivenessState* next_bytecode_in_liveness,
     173    18077542 :                        const interpreter::BytecodeArrayAccessor& accessor,
     174             :                        const BytecodeLivenessMap& liveness_map) {
     175             :   int current_offset = accessor.current_offset();
     176             :   const Handle<BytecodeArray>& bytecode_array = accessor.bytecode_array();
     177             : 
     178             :   // Update from jump target (if any). Skip loops, we update these manually in
     179             :   // the liveness iterations.
     180    18077542 :   if (Bytecodes::IsForwardJump(bytecode)) {
     181      964585 :     int target_offset = accessor.GetJumpTargetOffset();
     182             :     out_liveness.Union(*liveness_map.GetInLiveness(target_offset));
     183    17112957 :   } else if (Bytecodes::IsSwitch(bytecode)) {
     184       25903 :     for (const auto& entry : accessor.GetJumpTableTargetOffsets()) {
     185       17835 :       out_liveness.Union(*liveness_map.GetInLiveness(entry.target_offset));
     186             :     }
     187             :   }
     188             : 
     189             :   // Update from next bytecode (unless there isn't one or this is an
     190             :   // unconditional jump).
     191    35652108 :   if (next_bytecode_in_liveness != nullptr &&
     192             :       !Bytecodes::IsUnconditionalJump(bytecode)) {
     193             :     out_liveness.Union(*next_bytecode_in_liveness);
     194             :   }
     195             : 
     196             :   // Update from exception handler (if any).
     197    18077540 :   if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) {
     198             :     int handler_context;
     199             :     // TODO(leszeks): We should look up this range only once per entry.
     200             :     HandlerTable* table = HandlerTable::cast(bytecode_array->handler_table());
     201             :     int handler_offset =
     202     7581194 :         table->LookupRange(current_offset, &handler_context, nullptr);
     203             : 
     204     7581193 :     if (handler_offset != -1) {
     205             :       bool was_accumulator_live = out_liveness.AccumulatorIsLive();
     206             :       out_liveness.Union(*liveness_map.GetInLiveness(handler_offset));
     207      349590 :       out_liveness.MarkRegisterLive(handler_context);
     208      349590 :       if (!was_accumulator_live) {
     209             :         // The accumulator is reset to the exception on entry into a handler,
     210             :         // and so shouldn't be considered live coming out of this bytecode just
     211             :         // because it's live coming into the handler. So, kill the accumulator
     212             :         // if the handler is the only thing that made it live.
     213             :         out_liveness.MarkAccumulatorDead();
     214             : 
     215             :         // TODO(leszeks): Ideally the accumulator wouldn't be considered live at
     216             :         // the start of the handler, but looking up if the current bytecode is
     217             :         // the start of a handler is not free, so we should only do it if we
     218             :         // decide it's necessary.
     219             :       }
     220             :     }
     221             :   }
     222    18077533 : }
     223             : 
     224     2030219 : void UpdateAssignments(Bytecode bytecode, BytecodeLoopAssignments& assignments,
     225             :                        const interpreter::BytecodeArrayAccessor& accessor) {
     226             :   int num_operands = Bytecodes::NumberOfOperands(bytecode);
     227             :   const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode);
     228             : 
     229     4829224 :   for (int i = 0; i < num_operands; ++i) {
     230     2799005 :     switch (operand_types[i]) {
     231             :       case OperandType::kRegOut: {
     232      586812 :         assignments.Add(accessor.GetRegisterOperand(i));
     233      586812 :         break;
     234             :       }
     235             :       case OperandType::kRegOutList: {
     236         453 :         interpreter::Register r = accessor.GetRegisterOperand(i++);
     237         453 :         uint32_t reg_count = accessor.GetRegisterCountOperand(i);
     238         453 :         assignments.AddList(r, reg_count);
     239             :         break;
     240             :       }
     241             :       case OperandType::kRegOutPair: {
     242          25 :         assignments.AddList(accessor.GetRegisterOperand(i), 2);
     243          25 :         break;
     244             :       }
     245             :       case OperandType::kRegOutTriple: {
     246         207 :         assignments.AddList(accessor.GetRegisterOperand(i), 3);
     247         207 :         break;
     248             :       }
     249             :       default:
     250             :         DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i]));
     251             :         break;
     252             :     }
     253             :   }
     254     2030219 : }
     255             : 
     256             : }  // namespace
     257             : 
     258    17018050 : void BytecodeAnalysis::Analyze(BailoutId osr_bailout_id) {
     259     1009836 :   loop_stack_.push({-1, nullptr});
     260             : 
     261             :   BytecodeLivenessState* next_bytecode_in_liveness = nullptr;
     262             : 
     263             :   int osr_loop_end_offset =
     264      504919 :       osr_bailout_id.IsNone() ? -1 : osr_bailout_id.ToInt();
     265             : 
     266      504919 :   interpreter::BytecodeArrayRandomIterator iterator(bytecode_array(), zone());
     267    16648644 :   for (iterator.GoToEnd(); iterator.IsValid(); --iterator) {
     268    16143720 :     Bytecode bytecode = iterator.current_bytecode();
     269    16143720 :     int current_offset = iterator.current_offset();
     270             : 
     271    16143720 :     if (bytecode == Bytecode::kJumpLoop) {
     272             :       // Every byte up to and including the last byte within the backwards jump
     273             :       // instruction is considered part of the loop, set loop end accordingly.
     274       61601 :       int loop_end = current_offset + iterator.current_bytecode_size();
     275       61601 :       int loop_header = iterator.GetJumpTargetOffset();
     276       61601 :       PushLoop(loop_header, loop_end);
     277             : 
     278       61601 :       if (current_offset == osr_loop_end_offset) {
     279        5809 :         osr_entry_point_ = loop_header;
     280             :       } else if (current_offset < osr_loop_end_offset) {
     281             :         // Check we've found the osr_entry_point if we've gone past the
     282             :         // osr_loop_end_offset. Note, we are iterating the bytecode in reverse,
     283             :         // so the less than in the check is correct.
     284             :         DCHECK_NE(-1, osr_entry_point_);
     285             :       }
     286             : 
     287             :       // Save the index so that we can do another pass later.
     288       61601 :       if (do_liveness_analysis_) {
     289      122432 :         loop_end_index_queue_.push_back(iterator.current_index());
     290             :       }
     291    16082119 :     } else if (loop_stack_.size() > 1) {
     292             :       LoopStackEntry& current_loop = loop_stack_.top();
     293     2030219 :       LoopInfo* current_loop_info = current_loop.loop_info;
     294             : 
     295             :       // TODO(leszeks): Ideally, we'd only set values that were assigned in
     296             :       // the loop *and* are live when the loop exits. However, this requires
     297             :       // tracking the out-liveness of *all* loop exits, which is not
     298             :       // information we currently have.
     299     2030219 :       UpdateAssignments(bytecode, current_loop_info->assignments(), iterator);
     300             : 
     301     2030219 :       if (current_offset == current_loop.header_offset) {
     302             :         loop_stack_.pop();
     303       61592 :         if (loop_stack_.size() > 1) {
     304             :           // Propagate inner loop assignments to outer loop.
     305        8505 :           loop_stack_.top().loop_info->assignments().Union(
     306             :               current_loop_info->assignments());
     307             :         }
     308             :       }
     309             :     }
     310             : 
     311    16143711 :     if (do_liveness_analysis_) {
     312             :       BytecodeLiveness& liveness = liveness_map_.InitializeLiveness(
     313    16008214 :           current_offset, bytecode_array()->register_count(), zone());
     314             : 
     315             :       UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness,
     316    16008227 :                         iterator, liveness_map_);
     317    16008225 :       liveness.in->CopyFrom(*liveness.out);
     318    16008222 :       UpdateInLiveness(bytecode, *liveness.in, iterator);
     319             : 
     320    16008221 :       next_bytecode_in_liveness = liveness.in;
     321             :     }
     322             :   }
     323             : 
     324             :   DCHECK_EQ(loop_stack_.size(), 1u);
     325             :   DCHECK_EQ(loop_stack_.top().header_offset, -1);
     326             : 
     327     1009834 :   if (!do_liveness_analysis_) return;
     328             : 
     329             :   // At this point, every bytecode has a valid in and out liveness, except for
     330             :   // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness
     331             :   // analysis iterations can only add additional liveness bits that are pulled
     332             :   // across these back edges.
     333             :   //
     334             :   // Furthermore, a loop header's in-liveness can only change based on any
     335             :   // bytecodes *after* the loop end --  it cannot change as a result of the
     336             :   // JumpLoop liveness being updated, as the only liveness bits than can be
     337             :   // added to the loop body are those of the loop header.
     338             :   //
     339             :   // So, if we know that the liveness of bytecodes after a loop header won't
     340             :   // change (e.g. because there are no loops in them, or we have already ensured
     341             :   // those loops are valid), we can safely update the loop end and pass over the
     342             :   // loop body, and then never have to pass over that loop end again, because we
     343             :   // have shown that its target, the loop header, can't change from the entries
     344             :   // after the loop, and can't change from any loop body pass.
     345             :   //
     346             :   // This means that in a pass, we can iterate backwards over the bytecode
     347             :   // array, process any loops that we encounter, and on subsequent passes we can
     348             :   // skip processing those loops (though we still have to process inner loops).
     349             :   //
     350             :   // Equivalently, we can queue up loop ends from back to front, and pass over
     351             :   // the loops in that order, as this preserves both the bottom-to-top and
     352             :   // outer-to-inner requirements.
     353             : 
     354     1067160 :   for (int loop_end_index : loop_end_index_queue_) {
     355             :     iterator.GoToIndex(loop_end_index);
     356             : 
     357             :     DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop);
     358             : 
     359       61216 :     int header_offset = iterator.GetJumpTargetOffset();
     360       61216 :     int end_offset = iterator.current_offset();
     361             : 
     362             :     BytecodeLiveness& header_liveness =
     363       61216 :         liveness_map_.GetLiveness(header_offset);
     364       61216 :     BytecodeLiveness& end_liveness = liveness_map_.GetLiveness(end_offset);
     365             : 
     366      122432 :     if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) {
     367             :       // Only update the loop body if the loop end liveness changed.
     368             :       continue;
     369             :     }
     370       56133 :     end_liveness.in->CopyFrom(*end_liveness.out);
     371       56133 :     next_bytecode_in_liveness = end_liveness.in;
     372             : 
     373             :     // Advance into the loop body.
     374             :     --iterator;
     375     2069311 :     for (; iterator.current_offset() > header_offset; --iterator) {
     376     2013178 :       Bytecode bytecode = iterator.current_bytecode();
     377             : 
     378     2013178 :       int current_offset = iterator.current_offset();
     379     2013178 :       BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset);
     380             : 
     381             :       UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness,
     382     2013178 :                         iterator, liveness_map_);
     383     2013178 :       liveness.in->CopyFrom(*liveness.out);
     384     2013178 :       UpdateInLiveness(bytecode, *liveness.in, iterator);
     385             : 
     386     2013178 :       next_bytecode_in_liveness = liveness.in;
     387             :     }
     388             :     // Now we are at the loop header. Since the in-liveness of the header
     389             :     // can't change, we need only to update the out-liveness.
     390             :     UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out,
     391       56133 :                       next_bytecode_in_liveness, iterator, liveness_map_);
     392             :   }
     393             : 
     394             :   DCHECK(LivenessIsValid());
     395             : }
     396             : 
     397       61601 : void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) {
     398             :   DCHECK(loop_header < loop_end);
     399             :   DCHECK(loop_stack_.top().header_offset < loop_header);
     400             :   DCHECK(end_to_header_.find(loop_end) == end_to_header_.end());
     401             :   DCHECK(header_to_info_.find(loop_header) == header_to_info_.end());
     402             : 
     403       61601 :   int parent_offset = loop_stack_.top().header_offset;
     404             : 
     405       61601 :   end_to_header_.insert({loop_end, loop_header});
     406             :   auto it = header_to_info_.insert(
     407             :       {loop_header, LoopInfo(parent_offset, bytecode_array_->parameter_count(),
     408      123202 :                              bytecode_array_->register_count(), zone_)});
     409             :   // Get the loop info pointer from the output of insert.
     410       61601 :   LoopInfo* loop_info = &it.first->second;
     411             : 
     412      123202 :   loop_stack_.push({loop_header, loop_info});
     413       61601 : }
     414             : 
     415    13997804 : bool BytecodeAnalysis::IsLoopHeader(int offset) const {
     416    13997805 :   return header_to_info_.find(offset) != header_to_info_.end();
     417             : }
     418             : 
     419     2061538 : int BytecodeAnalysis::GetLoopOffsetFor(int offset) const {
     420             :   auto loop_end_to_header = end_to_header_.upper_bound(offset);
     421             :   // If there is no next end => offset is not in a loop.
     422     2061538 :   if (loop_end_to_header == end_to_header_.end()) {
     423             :     return -1;
     424             :   }
     425             :   // If the header precedes the offset, this is the loop
     426             :   //
     427             :   //   .> header  <--loop_end_to_header
     428             :   //   |
     429             :   //   |  <--offset
     430             :   //   |
     431             :   //   `- end
     432      653880 :   if (loop_end_to_header->second <= offset) {
     433             :     return loop_end_to_header->second;
     434             :   }
     435             :   // Otherwise there is a (potentially nested) loop after this offset.
     436             :   //
     437             :   //    <--offset
     438             :   //
     439             :   //   .> header
     440             :   //   |
     441             :   //   | .> header  <--loop_end_to_header
     442             :   //   | |
     443             :   //   | `- end
     444             :   //   |
     445             :   //   `- end
     446             :   // We just return the parent of the next loop (might be -1).
     447             :   DCHECK(header_to_info_.upper_bound(offset) != header_to_info_.end());
     448             : 
     449      351647 :   return header_to_info_.upper_bound(offset)->second.parent_offset();
     450             : }
     451             : 
     452      189439 : const LoopInfo& BytecodeAnalysis::GetLoopInfoFor(int header_offset) const {
     453             :   DCHECK(IsLoopHeader(header_offset));
     454             : 
     455      189439 :   return header_to_info_.find(header_offset)->second;
     456             : }
     457             : 
     458     5087174 : const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor(
     459             :     int offset) const {
     460     5087174 :   if (!do_liveness_analysis_) return nullptr;
     461             : 
     462    10074129 :   return liveness_map_.GetInLiveness(offset);
     463             : }
     464             : 
     465     3649569 : const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor(
     466             :     int offset) const {
     467     3649569 :   if (!do_liveness_analysis_) return nullptr;
     468             : 
     469     7230692 :   return liveness_map_.GetOutLiveness(offset);
     470             : }
     471             : 
     472           0 : std::ostream& BytecodeAnalysis::PrintLivenessTo(std::ostream& os) const {
     473           0 :   interpreter::BytecodeArrayIterator iterator(bytecode_array());
     474             : 
     475           0 :   for (; !iterator.done(); iterator.Advance()) {
     476           0 :     int current_offset = iterator.current_offset();
     477             : 
     478           0 :     const BitVector& in_liveness =
     479             :         GetInLivenessFor(current_offset)->bit_vector();
     480           0 :     const BitVector& out_liveness =
     481             :         GetOutLivenessFor(current_offset)->bit_vector();
     482             : 
     483           0 :     for (int i = 0; i < in_liveness.length(); ++i) {
     484           0 :       os << (in_liveness.Contains(i) ? "L" : ".");
     485             :     }
     486           0 :     os << " -> ";
     487             : 
     488           0 :     for (int i = 0; i < out_liveness.length(); ++i) {
     489           0 :       os << (out_liveness.Contains(i) ? "L" : ".");
     490             :     }
     491             : 
     492           0 :     os << " | " << current_offset << ": ";
     493           0 :     iterator.PrintTo(os) << std::endl;
     494             :   }
     495             : 
     496           0 :   return os;
     497             : }
     498             : 
     499             : #if DEBUG
     500             : bool BytecodeAnalysis::LivenessIsValid() {
     501             :   interpreter::BytecodeArrayRandomIterator iterator(bytecode_array(), zone());
     502             : 
     503             :   BytecodeLivenessState previous_liveness(bytecode_array()->register_count(),
     504             :                                           zone());
     505             : 
     506             :   int invalid_offset = -1;
     507             :   int which_invalid = -1;
     508             : 
     509             :   BytecodeLivenessState* next_bytecode_in_liveness = nullptr;
     510             : 
     511             :   // Ensure that there are no liveness changes if we iterate one more time.
     512             :   for (iterator.GoToEnd(); iterator.IsValid(); --iterator) {
     513             :     Bytecode bytecode = iterator.current_bytecode();
     514             : 
     515             :     int current_offset = iterator.current_offset();
     516             : 
     517             :     BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset);
     518             : 
     519             :     previous_liveness.CopyFrom(*liveness.out);
     520             : 
     521             :     UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness,
     522             :                       iterator, liveness_map_);
     523             :     // UpdateOutLiveness skips kJumpLoop, so we update it manually.
     524             :     if (bytecode == Bytecode::kJumpLoop) {
     525             :       int target_offset = iterator.GetJumpTargetOffset();
     526             :       liveness.out->Union(*liveness_map_.GetInLiveness(target_offset));
     527             :     }
     528             : 
     529             :     if (!liveness.out->Equals(previous_liveness)) {
     530             :       // Reset the invalid liveness.
     531             :       liveness.out->CopyFrom(previous_liveness);
     532             :       invalid_offset = current_offset;
     533             :       which_invalid = 1;
     534             :       break;
     535             :     }
     536             : 
     537             :     previous_liveness.CopyFrom(*liveness.in);
     538             : 
     539             :     liveness.in->CopyFrom(*liveness.out);
     540             :     UpdateInLiveness(bytecode, *liveness.in, iterator);
     541             : 
     542             :     if (!liveness.in->Equals(previous_liveness)) {
     543             :       // Reset the invalid liveness.
     544             :       liveness.in->CopyFrom(previous_liveness);
     545             :       invalid_offset = current_offset;
     546             :       which_invalid = 0;
     547             :       break;
     548             :     }
     549             : 
     550             :     next_bytecode_in_liveness = liveness.in;
     551             :   }
     552             : 
     553             :   // Ensure that the accumulator is not live when jumping out of a loop, or on
     554             :   // the back-edge of a loop.
     555             :   for (iterator.GoToStart(); iterator.IsValid() && invalid_offset == -1;
     556             :        ++iterator) {
     557             :     Bytecode bytecode = iterator.current_bytecode();
     558             :     int current_offset = iterator.current_offset();
     559             :     int loop_header = GetLoopOffsetFor(current_offset);
     560             : 
     561             :     // We only care if we're inside a loop.
     562             :     if (loop_header == -1) continue;
     563             : 
     564             :     // We only care about jumps.
     565             :     if (!Bytecodes::IsJump(bytecode)) continue;
     566             : 
     567             :     int jump_target = iterator.GetJumpTargetOffset();
     568             : 
     569             :     // If this is a forward jump to somewhere else in the same loop, ignore it.
     570             :     if (Bytecodes::IsForwardJump(bytecode) &&
     571             :         GetLoopOffsetFor(jump_target) == loop_header) {
     572             :       continue;
     573             :     }
     574             : 
     575             :     // The accumulator must be dead at the start of the target of the jump.
     576             :     if (liveness_map_.GetLiveness(jump_target).in->AccumulatorIsLive()) {
     577             :       invalid_offset = jump_target;
     578             :       which_invalid = 0;
     579             :       break;
     580             :     }
     581             :   }
     582             : 
     583             :   if (invalid_offset != -1) {
     584             :     OFStream of(stderr);
     585             :     of << "Invalid liveness:" << std::endl;
     586             : 
     587             :     // Dump the bytecode, annotated with the liveness and marking loops.
     588             : 
     589             :     int loop_indent = 0;
     590             : 
     591             :     interpreter::BytecodeArrayIterator forward_iterator(bytecode_array());
     592             :     for (; !forward_iterator.done(); forward_iterator.Advance()) {
     593             :       int current_offset = forward_iterator.current_offset();
     594             :       const BitVector& in_liveness =
     595             :           GetInLivenessFor(current_offset)->bit_vector();
     596             :       const BitVector& out_liveness =
     597             :           GetOutLivenessFor(current_offset)->bit_vector();
     598             : 
     599             :       for (int i = 0; i < in_liveness.length(); ++i) {
     600             :         of << (in_liveness.Contains(i) ? 'L' : '.');
     601             :       }
     602             : 
     603             :       of << " | ";
     604             : 
     605             :       for (int i = 0; i < out_liveness.length(); ++i) {
     606             :         of << (out_liveness.Contains(i) ? 'L' : '.');
     607             :       }
     608             : 
     609             :       of << " : " << current_offset << " : ";
     610             : 
     611             :       // Draw loop back edges by indentin everything between loop headers and
     612             :       // jump loop instructions.
     613             :       if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) {
     614             :         loop_indent--;
     615             :       }
     616             :       for (int i = 0; i < loop_indent; ++i) {
     617             :         of << "| ";
     618             :       }
     619             :       if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) {
     620             :         of << "`-";
     621             :       } else if (IsLoopHeader(current_offset)) {
     622             :         of << ".>";
     623             :         loop_indent++;
     624             :       }
     625             :       forward_iterator.PrintTo(of);
     626             :       if (Bytecodes::IsJump(forward_iterator.current_bytecode())) {
     627             :         of << " (@" << forward_iterator.GetJumpTargetOffset() << ")";
     628             :       }
     629             :       of << std::endl;
     630             : 
     631             :       if (current_offset == invalid_offset) {
     632             :         // Underline the invalid liveness.
     633             :         if (which_invalid == 0) {
     634             :           for (int i = 0; i < in_liveness.length(); ++i) {
     635             :             of << '^';
     636             :           }
     637             :           for (int i = 0; i < out_liveness.length() + 3; ++i) {
     638             :             of << ' ';
     639             :           }
     640             :         } else {
     641             :           for (int i = 0; i < in_liveness.length() + 3; ++i) {
     642             :             of << ' ';
     643             :           }
     644             :           for (int i = 0; i < out_liveness.length(); ++i) {
     645             :             of << '^';
     646             :           }
     647             :         }
     648             : 
     649             :         // Make sure to draw the loop indentation marks on this additional line.
     650             :         of << " : " << current_offset << " : ";
     651             :         for (int i = 0; i < loop_indent; ++i) {
     652             :           of << "| ";
     653             :         }
     654             : 
     655             :         of << std::endl;
     656             :       }
     657             :     }
     658             :   }
     659             : 
     660             :   return invalid_offset == -1;
     661             : }
     662             : #endif
     663             : 
     664             : }  // namespace compiler
     665             : }  // namespace internal
     666             : }  // namespace v8

Generated by: LCOV version 1.10