/ bytecode / PreciseJumpTargets.cpp
PreciseJumpTargets.cpp
  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. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 24   */
 25  
 26  #include "config.h"
 27  #include "PreciseJumpTargets.h"
 28  
 29  #include "JSCJSValueInlines.h"
 30  #include "PreciseJumpTargetsInlines.h"
 31  
 32  namespace JSC {
 33  
 34  template <size_t vectorSize, typename Block>
 35  static void getJumpTargetsForInstruction(Block* codeBlock, const InstructionStream::Ref& instruction, Vector<InstructionStream::Offset, vectorSize>& out)
 36  {
 37      extractStoredJumpTargetsForInstruction(codeBlock, instruction, [&](int32_t relativeOffset) {
 38          out.append(instruction.offset() + relativeOffset);
 39      });
 40      OpcodeID opcodeID = instruction->opcodeID();
 41      // op_loop_hint does not have jump target stored in bytecode instructions.
 42      if (opcodeID == op_loop_hint)
 43          out.append(instruction.offset());
 44      else if (opcodeID == op_enter && codeBlock->hasTailCalls() && Options::optimizeRecursiveTailCalls()) {
 45          // We need to insert a jump after op_enter, so recursive tail calls have somewhere to jump to.
 46          // But we only want to pay that price for functions that have at least one tail call.
 47          out.append(instruction.next().offset());
 48      }
 49  }
 50  
 51  enum class ComputePreciseJumpTargetsMode {
 52      FollowCodeBlockClaim,
 53      ForceCompute,
 54  };
 55  
 56  template<ComputePreciseJumpTargetsMode Mode, typename Block, size_t vectorSize>
 57  void computePreciseJumpTargetsInternal(Block* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset, vectorSize>& out)
 58  {
 59      ASSERT(out.isEmpty());
 60  
 61      // The code block has a superset of the jump targets. So if it claims to have none, we are done.
 62      if (Mode == ComputePreciseJumpTargetsMode::FollowCodeBlockClaim && !codeBlock->numberOfJumpTargets())
 63          return;
 64      
 65      for (unsigned i = codeBlock->numberOfExceptionHandlers(); i--;) {
 66          out.append(codeBlock->exceptionHandler(i).target);
 67          out.append(codeBlock->exceptionHandler(i).start);
 68          out.append(codeBlock->exceptionHandler(i).end);
 69      }
 70  
 71      for (const auto& instruction : instructions) {
 72          getJumpTargetsForInstruction(codeBlock, instruction, out);
 73      }
 74      
 75      std::sort(out.begin(), out.end());
 76      
 77      // We will have duplicates, and we must remove them.
 78      unsigned toIndex = 0;
 79      unsigned fromIndex = 0;
 80      unsigned lastValue = UINT_MAX;
 81      while (fromIndex < out.size()) {
 82          unsigned value = out[fromIndex++];
 83          if (value == lastValue)
 84              continue;
 85          out[toIndex++] = value;
 86          lastValue = value;
 87      }
 88      out.shrinkCapacity(toIndex);
 89  }
 90  
 91  void computePreciseJumpTargets(CodeBlock* codeBlock, Vector<InstructionStream::Offset, 32>& out)
 92  {
 93      computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::FollowCodeBlockClaim>(codeBlock, codeBlock->instructions(), out);
 94  }
 95  
 96  void computePreciseJumpTargets(CodeBlock* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset, 32>& out)
 97  {
 98      computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::FollowCodeBlockClaim>(codeBlock, instructions, out);
 99  }
100  
101  void computePreciseJumpTargets(UnlinkedCodeBlockGenerator* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset, 32>& out)
102  {
103      computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::FollowCodeBlockClaim>(codeBlock, instructions, out);
104  }
105  
106  void recomputePreciseJumpTargets(UnlinkedCodeBlockGenerator* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset>& out)
107  {
108      computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::ForceCompute>(codeBlock, instructions, out);
109  }
110  
111  void findJumpTargetsForInstruction(CodeBlock* codeBlock, const InstructionStream::Ref& instruction, Vector<InstructionStream::Offset, 1>& out)
112  {
113      getJumpTargetsForInstruction(codeBlock, instruction, out);
114  }
115  
116  void findJumpTargetsForInstruction(UnlinkedCodeBlockGenerator* codeBlock, const InstructionStream::Ref& instruction, Vector<InstructionStream::Offset, 1>& out)
117  {
118      getJumpTargetsForInstruction(codeBlock, instruction, out);
119  }
120  
121  } // namespace JSC
122