| /* | 
 |  * Copyright (C) 2013 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" | 
 |  | 
 | namespace JSC { | 
 |  | 
 | static void addSimpleSwitchTargets(SimpleJumpTable& jumpTable, unsigned bytecodeOffset, Vector<unsigned, 32>& out) | 
 | { | 
 |     for (unsigned i = jumpTable.branchOffsets.size(); i--;) | 
 |         out.append(bytecodeOffset + jumpTable.branchOffsets[i]); | 
 | } | 
 |  | 
 | void computePreciseJumpTargets(CodeBlock* codeBlock, Vector<unsigned, 32>& out) | 
 | { | 
 |     ASSERT(out.isEmpty()); | 
 |      | 
 |     // We will derive a superset of the jump targets that the code block thinks it has. | 
 |     // So, if the code block claims there are none, then we are done. | 
 |     if (!codeBlock->numberOfJumpTargets()) | 
 |         return; | 
 |      | 
 |     for (unsigned i = codeBlock->numberOfExceptionHandlers(); i--;) | 
 |         out.append(codeBlock->exceptionHandler(i).target); | 
 |      | 
 |     Interpreter* interpreter = codeBlock->vm()->interpreter; | 
 |     Instruction* instructionsBegin = codeBlock->instructions().begin(); | 
 |     unsigned instructionCount = codeBlock->instructions().size(); | 
 |     for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount;) { | 
 |         OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode); | 
 |         Instruction* current = instructionsBegin + bytecodeOffset; | 
 |         switch (opcodeID) { | 
 |         case op_jmp: | 
 |             out.append(bytecodeOffset + current[1].u.operand); | 
 |             break; | 
 |         case op_jtrue: | 
 |         case op_jfalse: | 
 |         case op_jeq_null: | 
 |         case op_jneq_null: | 
 |             out.append(bytecodeOffset + current[2].u.operand); | 
 |             break; | 
 |         case op_jneq_ptr: | 
 |         case op_jless: | 
 |         case op_jlesseq: | 
 |         case op_jgreater: | 
 |         case op_jgreatereq: | 
 |         case op_jnless: | 
 |         case op_jnlesseq: | 
 |         case op_jngreater: | 
 |         case op_jngreatereq: | 
 |             out.append(bytecodeOffset + current[3].u.operand); | 
 |             break; | 
 |         case op_switch_imm: | 
 |             addSimpleSwitchTargets(codeBlock->immediateSwitchJumpTable(current[1].u.operand), bytecodeOffset, out); | 
 |             out.append(bytecodeOffset + current[2].u.operand); | 
 |             break; | 
 |         case op_switch_char: | 
 |             addSimpleSwitchTargets(codeBlock->characterSwitchJumpTable(current[1].u.operand), bytecodeOffset, out); | 
 |             out.append(bytecodeOffset + current[2].u.operand); | 
 |             break; | 
 |         case op_switch_string: { | 
 |             StringJumpTable& table = codeBlock->stringSwitchJumpTable(current[1].u.operand); | 
 |             StringJumpTable::StringOffsetTable::iterator iter = table.offsetTable.begin(); | 
 |             StringJumpTable::StringOffsetTable::iterator end = table.offsetTable.end(); | 
 |             for (; iter != end; ++iter) | 
 |                 out.append(bytecodeOffset + iter->value.branchOffset); | 
 |             out.append(bytecodeOffset + current[2].u.operand); | 
 |             break; | 
 |         } | 
 |         case op_get_pnames: | 
 |             out.append(bytecodeOffset + current[5].u.operand); | 
 |             break; | 
 |         case op_next_pname: | 
 |             out.append(bytecodeOffset + current[6].u.operand); | 
 |             break; | 
 |         case op_check_has_instance: | 
 |             out.append(bytecodeOffset + current[4].u.operand); | 
 |             break; | 
 |         case op_loop_hint: | 
 |             out.append(bytecodeOffset); | 
 |             break; | 
 |         default: | 
 |             break; | 
 |         } | 
 |         bytecodeOffset += opcodeLengths[opcodeID]; | 
 |     } | 
 |      | 
 |     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.resize(toIndex); | 
 | } | 
 |  | 
 | } // namespace JSC | 
 |  |