/ bytecode / BytecodeLivenessAnalysisInlines.h
BytecodeLivenessAnalysisInlines.h
  1  /*
  2   * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 14   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 15   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 17   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 18   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 19   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 20   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 21   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 22   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 23   * THE POSSIBILITY OF SUCH DAMAGE.
 24   */
 25  
 26  #pragma once
 27  
 28  #include "BytecodeGraph.h"
 29  #include "BytecodeLivenessAnalysis.h"
 30  #include "BytecodeUseDef.h"
 31  #include "CodeBlock.h"
 32  #include "InterpreterInlines.h"
 33  
 34  namespace JSC {
 35  
 36  inline bool virtualRegisterIsAlwaysLive(VirtualRegister reg)
 37  {
 38      return !reg.isLocal();
 39  }
 40  
 41  inline bool virtualRegisterThatIsNotAlwaysLiveIsLive(const FastBitVector& out, VirtualRegister reg)
 42  {
 43      unsigned local = reg.toLocal();
 44      if (local >= out.numBits())
 45          return false;
 46      return out[local];
 47  }
 48  
 49  inline bool virtualRegisterIsLive(const FastBitVector& out, VirtualRegister operand)
 50  {
 51      return virtualRegisterIsAlwaysLive(operand) || virtualRegisterThatIsNotAlwaysLiveIsLive(out, operand);
 52  }
 53  
 54  inline bool isValidRegisterForLiveness(VirtualRegister operand)
 55  {
 56      if (operand.isConstant())
 57          return false;
 58      return operand.isLocal();
 59  }
 60  
 61  template<typename CodeBlockType, typename DefFunctor>
 62  inline void BytecodeLivenessPropagation::stepOverBytecodeIndexDef(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph&, BytecodeIndex bytecodeIndex, const DefFunctor& def)
 63  {
 64      auto* instruction = instructions.at(bytecodeIndex).ptr();
 65      computeDefsForBytecodeIndex(
 66          codeBlock, instruction, bytecodeIndex.checkpoint(),
 67          [&] (VirtualRegister operand) {
 68              if (isValidRegisterForLiveness(operand))
 69                  def(operand.toLocal());
 70          });
 71  }
 72  
 73  template<typename CodeBlockType, typename UseFunctor>
 74  inline void BytecodeLivenessPropagation::stepOverBytecodeIndexUse(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph&, BytecodeIndex bytecodeIndex, const UseFunctor& use)
 75  {
 76      auto* instruction = instructions.at(bytecodeIndex).ptr();
 77      computeUsesForBytecodeIndex(
 78          codeBlock, instruction, bytecodeIndex.checkpoint(),
 79          [&] (VirtualRegister operand) {
 80              if (isValidRegisterForLiveness(operand))
 81                  use(operand.toLocal());
 82          });
 83  }
 84  
 85  template<typename CodeBlockType, typename UseFunctor>
 86  inline void BytecodeLivenessPropagation::stepOverBytecodeIndexUseInExceptionHandler(CodeBlockType* codeBlock, const InstructionStream&, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, const UseFunctor& use)
 87  {
 88      // If we have an exception handler, we want the live-in variables of the 
 89      // exception handler block to be included in the live-in of this particular BytecodeIndex.
 90      if (auto* handler = codeBlock->handlerForBytecodeIndex(bytecodeIndex)) {
 91          BytecodeBasicBlock* handlerBlock = graph.findBasicBlockWithLeaderOffset(handler->target);
 92          ASSERT(handlerBlock);
 93          handlerBlock->in().forEachSetBit(use);
 94      }
 95  }
 96  
 97  // Simplified interface to bytecode use/def, which determines defs first and then uses, and includes
 98  // exception handlers in the uses.
 99  template<typename CodeBlockType, typename UseFunctor, typename DefFunctor>
100  inline void BytecodeLivenessPropagation::stepOverBytecodeIndex(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, const UseFunctor& use, const DefFunctor& def)
101  {
102      // This abstractly executes the BytecodeIndex in reverse. Instructions logically first use operands and
103      // then define operands. This logical ordering is necessary for operations that use and def the same
104      // operand, like:
105      //
106      //     op_add loc1, loc1, loc2
107      //
108      // The use of loc1 happens before the def of loc1. That's a semantic requirement since the add
109      // operation cannot travel forward in time to read the value that it will produce after reading that
110      // value. Since we are executing in reverse, this means that we must do defs before uses (reverse of
111      // uses before defs).
112      //
113      // Since this is a liveness analysis, this ordering ends up being particularly important: if we did
114      // uses before defs, then the add operation above would appear to not have loc1 live, since we'd
115      // first add it to the out set (the use), and then we'd remove it (the def).
116  
117      stepOverBytecodeIndexDef(codeBlock, instructions, graph, bytecodeIndex, def);
118      stepOverBytecodeIndexUseInExceptionHandler(codeBlock, instructions, graph, bytecodeIndex, use);
119      stepOverBytecodeIndexUse(codeBlock, instructions, graph, bytecodeIndex, use);
120  }
121  
122  template<typename CodeBlockType>
123  inline void BytecodeLivenessPropagation::stepOverInstruction(CodeBlockType* codeBlock, const InstructionStream& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex, FastBitVector& out)
124  {
125      auto numberOfCheckpoints = instructions.at(bytecodeIndex)->numberOfCheckpoints();
126      for (Checkpoint checkpoint = numberOfCheckpoints; checkpoint--;) {
127          stepOverBytecodeIndex(
128              codeBlock, instructions, graph, bytecodeIndex.withCheckpoint(checkpoint),
129              [&] (unsigned bitIndex) {
130                  // This is the use functor, so we set the bit.
131                  out[bitIndex] = true;
132              },
133              [&] (unsigned bitIndex) {
134                  // This is the def functor, so we clear the bit.
135                  out[bitIndex] = false;
136              });
137      }
138  }
139  
140  template<typename CodeBlockType, typename Instructions>
141  inline bool BytecodeLivenessPropagation::computeLocalLivenessForInstruction(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeBasicBlock& block, BytecodeIndex targetIndex, FastBitVector& result)
142  {
143      ASSERT(!block.isExitBlock());
144      ASSERT(!block.isEntryBlock());
145      ASSERT_WITH_MESSAGE(!targetIndex.checkpoint(), "computeLocalLivenessForInstruction can't be used to ask questions about checkpoints");
146  
147      FastBitVector out = block.out();
148  
149      unsigned cursor = block.totalLength();
150      for (unsigned i = block.delta().size(); i--;) {
151          cursor -= block.delta()[i];
152          BytecodeIndex bytecodeIndex = BytecodeIndex(block.leaderOffset() + cursor);
153          if (targetIndex.offset() > bytecodeIndex.offset())
154              break;
155          stepOverInstruction(codeBlock, instructions, graph, bytecodeIndex, out);
156      }
157  
158      return result.setAndCheck(out);
159  }
160  
161  template<typename CodeBlockType, typename Instructions>
162  inline bool BytecodeLivenessPropagation::computeLocalLivenessForBlock(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeBasicBlock& block)
163  {
164      if (block.isExitBlock() || block.isEntryBlock())
165          return false;
166      return computeLocalLivenessForInstruction(codeBlock, instructions, graph, block, BytecodeIndex(block.leaderOffset()), block.in());
167  }
168  
169  template<typename CodeBlockType, typename Instructions>
170  inline FastBitVector BytecodeLivenessPropagation::getLivenessInfoAtInstruction(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph, BytecodeIndex bytecodeIndex)
171  {
172      ASSERT_WITH_MESSAGE(!bytecodeIndex.checkpoint(), "getLivenessInfoAtInstruction can't be used to ask questions about checkpoints");
173      BytecodeBasicBlock* block = graph.findBasicBlockForBytecodeOffset(bytecodeIndex.offset());
174      ASSERT(block);
175      ASSERT(!block->isEntryBlock());
176      ASSERT(!block->isExitBlock());
177      FastBitVector out;
178      out.resize(block->out().numBits());
179      computeLocalLivenessForInstruction(codeBlock, instructions, graph, *block, bytecodeIndex, out);
180      return out;
181  }
182  
183  template<typename CodeBlockType, typename Instructions>
184  inline void BytecodeLivenessPropagation::runLivenessFixpoint(CodeBlockType* codeBlock, const Instructions& instructions, BytecodeGraph& graph)
185  {
186      unsigned numberOfVariables = codeBlock->numCalleeLocals();
187      for (BytecodeBasicBlock& block : graph) {
188          block.in().resize(numberOfVariables);
189          block.out().resize(numberOfVariables);
190          block.in().clearAll();
191          block.out().clearAll();
192      }
193  
194      bool changed;
195      BytecodeBasicBlock& lastBlock = graph.last();
196      lastBlock.in().clearAll();
197      lastBlock.out().clearAll();
198      FastBitVector newOut;
199      newOut.resize(lastBlock.out().numBits());
200      do {
201          changed = false;
202          for (BytecodeBasicBlock& block : graph.basicBlocksInReverseOrder()) {
203              newOut.clearAll();
204              for (unsigned blockIndex : block.successors()) {
205                  BytecodeBasicBlock& successor = graph[blockIndex];
206                  newOut |= successor.in();
207              }
208              block.out() = newOut;
209              changed |= computeLocalLivenessForBlock(codeBlock, instructions, graph, block);
210          }
211      } while (changed);
212  }
213  
214  } // namespace JSC