| /* | 
 |  * Copyright (C) 2013-2017 Apple Inc. All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
 |  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 | #include "PreciseJumpTargets.h" | 
 |  | 
 | #include "JSCJSValueInlines.h" | 
 | #include "PreciseJumpTargetsInlines.h" | 
 |  | 
 | namespace JSC { | 
 |  | 
 | template <size_t vectorSize, typename Block> | 
 | static void getJumpTargetsForInstruction(Block* codeBlock, const InstructionStream::Ref& instruction, Vector<InstructionStream::Offset, vectorSize>& out) | 
 | { | 
 |     extractStoredJumpTargetsForInstruction(codeBlock, instruction, [&](int32_t relativeOffset) { | 
 |         out.append(instruction.offset() + relativeOffset); | 
 |     }); | 
 |     OpcodeID opcodeID = instruction->opcodeID(); | 
 |     // op_loop_hint does not have jump target stored in bytecode instructions. | 
 |     if (opcodeID == op_loop_hint) | 
 |         out.append(instruction.offset()); | 
 |     else if (opcodeID == op_enter && codeBlock->hasTailCalls() && Options::optimizeRecursiveTailCalls()) { | 
 |         // We need to insert a jump after op_enter, so recursive tail calls have somewhere to jump to. | 
 |         // But we only want to pay that price for functions that have at least one tail call. | 
 |         out.append(instruction.next().offset()); | 
 |     } | 
 | } | 
 |  | 
 | enum class ComputePreciseJumpTargetsMode { | 
 |     FollowCodeBlockClaim, | 
 |     ForceCompute, | 
 | }; | 
 |  | 
 | template<ComputePreciseJumpTargetsMode Mode, typename Block, size_t vectorSize> | 
 | void computePreciseJumpTargetsInternal(Block* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset, vectorSize>& out) | 
 | { | 
 |     ASSERT(out.isEmpty()); | 
 |  | 
 |     // The code block has a superset of the jump targets. So if it claims to have none, we are done. | 
 |     if (Mode == ComputePreciseJumpTargetsMode::FollowCodeBlockClaim && !codeBlock->numberOfJumpTargets()) | 
 |         return; | 
 |      | 
 |     for (unsigned i = codeBlock->numberOfExceptionHandlers(); i--;) { | 
 |         out.append(codeBlock->exceptionHandler(i).target); | 
 |         out.append(codeBlock->exceptionHandler(i).start); | 
 |         out.append(codeBlock->exceptionHandler(i).end); | 
 |     } | 
 |  | 
 |     for (const auto& instruction : instructions) { | 
 |         getJumpTargetsForInstruction(codeBlock, instruction, out); | 
 |     } | 
 |      | 
 |     std::sort(out.begin(), out.end()); | 
 |      | 
 |     // We will have duplicates, and we must remove them. | 
 |     unsigned toIndex = 0; | 
 |     unsigned fromIndex = 0; | 
 |     unsigned lastValue = UINT_MAX; | 
 |     while (fromIndex < out.size()) { | 
 |         unsigned value = out[fromIndex++]; | 
 |         if (value == lastValue) | 
 |             continue; | 
 |         out[toIndex++] = value; | 
 |         lastValue = value; | 
 |     } | 
 |     out.shrinkCapacity(toIndex); | 
 | } | 
 |  | 
 | void computePreciseJumpTargets(CodeBlock* codeBlock, Vector<InstructionStream::Offset, 32>& out) | 
 | { | 
 |     computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::FollowCodeBlockClaim>(codeBlock, codeBlock->instructions(), out); | 
 | } | 
 |  | 
 | void computePreciseJumpTargets(CodeBlock* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset, 32>& out) | 
 | { | 
 |     computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::FollowCodeBlockClaim>(codeBlock, instructions, out); | 
 | } | 
 |  | 
 | void computePreciseJumpTargets(UnlinkedCodeBlockGenerator* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset, 32>& out) | 
 | { | 
 |     computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::FollowCodeBlockClaim>(codeBlock, instructions, out); | 
 | } | 
 |  | 
 | void recomputePreciseJumpTargets(UnlinkedCodeBlockGenerator* codeBlock, const InstructionStream& instructions, Vector<InstructionStream::Offset>& out) | 
 | { | 
 |     computePreciseJumpTargetsInternal<ComputePreciseJumpTargetsMode::ForceCompute>(codeBlock, instructions, out); | 
 | } | 
 |  | 
 | void findJumpTargetsForInstruction(CodeBlock* codeBlock, const InstructionStream::Ref& instruction, Vector<InstructionStream::Offset, 1>& out) | 
 | { | 
 |     getJumpTargetsForInstruction(codeBlock, instruction, out); | 
 | } | 
 |  | 
 | void findJumpTargetsForInstruction(UnlinkedCodeBlockGenerator* codeBlock, const InstructionStream::Ref& instruction, Vector<InstructionStream::Offset, 1>& out) | 
 | { | 
 |     getJumpTargetsForInstruction(codeBlock, instruction, out); | 
 | } | 
 |  | 
 | } // namespace JSC | 
 |  |