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