diff options
author | Brian Carlstrom <bdc@google.com> | 2014-08-05 12:46:17 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2014-08-05 12:51:13 -0700 |
commit | 870b4f2d70d67d6dbb7d0881d101c61bed8caad2 (patch) | |
tree | 7487dad3970556a040f88a49852a3dc9ed19bebd /vm/analysis/Liveness.cpp | |
parent | 76e15e367ae1189b6f641ba8d16ca92bd179dac0 (diff) | |
download | android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.gz android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.tar.bz2 android_dalvik-870b4f2d70d67d6dbb7d0881d101c61bed8caad2.zip |
Dalvik is dead, long live Dalvik!
croot
cd dalvik
repo start dalvik-is-dead-long-live-dalvik .
repo sync -c .
git rm -r README.txt
git rm -r dexopt
git rm -r tools/deadcode.py
git rm -r tools/dex-preopt
git rm -r tools/dexcheck
git rm -r tools/gdbjithelper
git rm -r unit-tests
git rm -r vm
git checkout HEAD vm/Common.h (needed by libdex)
git checkout HEAD vm/DalvikVersion.h (needed by libdex)
git checkout HEAD vm/Profile.h (needed by dmtracedump)
git add Android.mk (after removing vm, dexopt, and unit-tests references)
git commit -a -m 'Dalvik is dead, long live Dalvik!'
Bug: 14298175
Change-Id: I9dd13053677629d13496d4238af4374452cda415
Diffstat (limited to 'vm/analysis/Liveness.cpp')
-rw-r--r-- | vm/analysis/Liveness.cpp | 824 |
1 files changed, 0 insertions, 824 deletions
diff --git a/vm/analysis/Liveness.cpp b/vm/analysis/Liveness.cpp deleted file mode 100644 index 361d3cb39..000000000 --- a/vm/analysis/Liveness.cpp +++ /dev/null @@ -1,824 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * Liveness analysis for Dalvik bytecode. - */ -#include "Dalvik.h" -#include "analysis/Liveness.h" -#include "analysis/CodeVerify.h" - -static bool processInstruction(VerifierData* vdata, u4 curIdx, - BitVector* workBits); -static bool markDebugLocals(VerifierData* vdata); -static void dumpLiveState(const VerifierData* vdata, u4 curIdx, - const BitVector* workBits); - - -/* - * Create a table of instruction widths that indicate the width of the - * *previous* instruction. The values are copied from the width table - * in "vdata", not derived from the instruction stream. - * - * Caller must free the return value. - */ -static InstructionWidth* createBackwardWidthTable(VerifierData* vdata) -{ - InstructionWidth* widths; - - widths = (InstructionWidth*) - calloc(vdata->insnsSize, sizeof(InstructionWidth)); - if (widths == NULL) - return NULL; - - u4 insnWidth = 0; - for (u4 idx = 0; idx < vdata->insnsSize; ) { - widths[idx] = insnWidth; - insnWidth = dvmInsnGetWidth(vdata->insnFlags, idx); - idx += insnWidth; - } - - return widths; -} - -/* - * Compute the "liveness" of every register at all GC points. - */ -bool dvmComputeLiveness(VerifierData* vdata) -{ - const InsnFlags* insnFlags = vdata->insnFlags; - InstructionWidth* backwardWidth; - VfyBasicBlock* startGuess = NULL; - BitVector* workBits = NULL; - bool result = false; - - bool verbose = false; //= dvmWantVerboseVerification(vdata->method); - if (verbose) { - const Method* meth = vdata->method; - ALOGI("Computing liveness for %s.%s:%s", - meth->clazz->descriptor, meth->name, meth->shorty); - } - - assert(vdata->registerLines != NULL); - - backwardWidth = createBackwardWidthTable(vdata); - if (backwardWidth == NULL) - goto bail; - - /* - * Allocate space for intra-block work set. Does not include space - * for method result "registers", which aren't visible to the GC. - * (They would be made live by move-result and then die on the - * instruction immediately before it.) - */ - workBits = dvmAllocBitVector(vdata->insnRegCount, false); - if (workBits == NULL) - goto bail; - - /* - * We continue until all blocks have been visited, and no block - * requires further attention ("visited" is set and "changed" is - * clear). - * - * TODO: consider creating a "dense" array of basic blocks to make - * the walking faster. - */ - for (int iter = 0;;) { - VfyBasicBlock* workBlock = NULL; - - if (iter++ > 100000) { - LOG_VFY_METH(vdata->method, "oh dear"); - dvmAbort(); - } - - /* - * If a block is marked "changed", we stop and handle it. If it - * just hasn't been visited yet, we remember it but keep searching - * for one that has been changed. - * - * The thought here is that this is more likely to let us work - * from end to start, which reduces the amount of re-evaluation - * required (both by using "changed" as a work list, and by picking - * un-visited blocks from the tail end of the method). - */ - if (startGuess != NULL) { - assert(startGuess->changed); - workBlock = startGuess; - } else { - for (u4 idx = 0; idx < vdata->insnsSize; idx++) { - VfyBasicBlock* block = vdata->basicBlocks[idx]; - if (block == NULL) - continue; - - if (block->changed) { - workBlock = block; - break; - } else if (!block->visited) { - workBlock = block; - } - } - } - - if (workBlock == NULL) { - /* all done */ - break; - } - - assert(workBlock->changed || !workBlock->visited); - startGuess = NULL; - - /* - * Load work bits. These represent the liveness of registers - * after the last instruction in the block has finished executing. - */ - assert(workBlock->liveRegs != NULL); - dvmCopyBitVector(workBits, workBlock->liveRegs); - if (verbose) { - ALOGI("Loaded work bits from last=0x%04x", workBlock->lastAddr); - dumpLiveState(vdata, 0xfffd, workBlock->liveRegs); - dumpLiveState(vdata, 0xffff, workBits); - } - - /* - * Process a single basic block. - * - * If this instruction is a GC point, we want to save the result - * in the RegisterLine. - * - * We don't break basic blocks on every GC point -- in particular, - * instructions that might throw but have no "try" block don't - * end a basic block -- so there could be more than one GC point - * in a given basic block. - * - * We could change this, but it turns out to be not all that useful. - * At first glance it appears that we could share the liveness bit - * vector between the basic block struct and the register line, - * but the basic block needs to reflect the state *after* the - * instruction has finished, while the GC points need to describe - * the state before the instruction starts. - */ - u4 curIdx = workBlock->lastAddr; - while (true) { - if (!processInstruction(vdata, curIdx, workBits)) - goto bail; - - if (verbose) { - dumpLiveState(vdata, curIdx + 0x8000, workBits); - } - - if (dvmInsnIsGcPoint(insnFlags, curIdx)) { - BitVector* lineBits = vdata->registerLines[curIdx].liveRegs; - if (lineBits == NULL) { - lineBits = vdata->registerLines[curIdx].liveRegs = - dvmAllocBitVector(vdata->insnRegCount, false); - } - dvmCopyBitVector(lineBits, workBits); - } - - if (curIdx == workBlock->firstAddr) - break; - assert(curIdx >= backwardWidth[curIdx]); - curIdx -= backwardWidth[curIdx]; - } - - workBlock->visited = true; - workBlock->changed = false; - - if (verbose) { - dumpLiveState(vdata, curIdx, workBits); - } - - /* - * Merge changes to all predecessors. If the new bits don't match - * the old bits, set the "changed" flag. - */ - PointerSet* preds = workBlock->predecessors; - size_t numPreds = dvmPointerSetGetCount(preds); - unsigned int predIdx; - - for (predIdx = 0; predIdx < numPreds; predIdx++) { - VfyBasicBlock* pred = - (VfyBasicBlock*) dvmPointerSetGetEntry(preds, predIdx); - - pred->changed = dvmCheckMergeBitVectors(pred->liveRegs, workBits); - if (verbose) { - ALOGI("merging cur=%04x into pred last=%04x (ch=%d)", - curIdx, pred->lastAddr, pred->changed); - dumpLiveState(vdata, 0xfffa, pred->liveRegs); - dumpLiveState(vdata, 0xfffb, workBits); - } - - /* - * We want to set the "changed" flag on unvisited predecessors - * as a way of guiding the verifier through basic blocks in - * a reasonable order. We can't count on variable liveness - * changing, so we force "changed" to true even if it hasn't. - */ - if (!pred->visited) - pred->changed = true; - - /* - * Keep track of one of the changed blocks so we can start - * there instead of having to scan through the list. - */ - if (pred->changed) - startGuess = pred; - } - } - -#ifndef NDEBUG - /* - * Sanity check: verify that all GC point register lines have a - * liveness bit vector allocated. Also, we're not expecting non-GC - * points to have them. - */ - u4 checkIdx; - for (checkIdx = 0; checkIdx < vdata->insnsSize; ) { - if (dvmInsnIsGcPoint(insnFlags, checkIdx)) { - if (vdata->registerLines[checkIdx].liveRegs == NULL) { - LOG_VFY_METH(vdata->method, - "GLITCH: no liveRegs for GC point 0x%04x", checkIdx); - dvmAbort(); - } - } else if (vdata->registerLines[checkIdx].liveRegs != NULL) { - LOG_VFY_METH(vdata->method, - "GLITCH: liveRegs for non-GC point 0x%04x", checkIdx); - dvmAbort(); - } - u4 insnWidth = dvmInsnGetWidth(insnFlags, checkIdx); - checkIdx += insnWidth; - } -#endif - - /* - * Factor in the debug info, if any. - */ - if (!markDebugLocals(vdata)) - goto bail; - - result = true; - -bail: - free(backwardWidth); - dvmFreeBitVector(workBits); - return result; -} - - -/* - * Add a register to the LIVE set. - */ -static inline void GEN(BitVector* workBits, u4 regIndex) -{ - dvmSetBit(workBits, regIndex); -} - -/* - * Add a register pair to the LIVE set. - */ -static inline void GENW(BitVector* workBits, u4 regIndex) -{ - dvmSetBit(workBits, regIndex); - dvmSetBit(workBits, regIndex+1); -} - -/* - * Remove a register from the LIVE set. - */ -static inline void KILL(BitVector* workBits, u4 regIndex) -{ - dvmClearBit(workBits, regIndex); -} - -/* - * Remove a register pair from the LIVE set. - */ -static inline void KILLW(BitVector* workBits, u4 regIndex) -{ - dvmClearBit(workBits, regIndex); - dvmClearBit(workBits, regIndex+1); -} - -/* - * Process a single instruction. - * - * Returns "false" if something goes fatally wrong. - */ -static bool processInstruction(VerifierData* vdata, u4 insnIdx, - BitVector* workBits) -{ - const Method* meth = vdata->method; - const u2* insns = meth->insns + insnIdx; - DecodedInstruction decInsn; - - dexDecodeInstruction(insns, &decInsn); - - /* - * Add registers to the "GEN" or "KILL" sets. We want to do KILL - * before GEN to handle cases where the source and destination - * register is the same. - */ - switch (decInsn.opcode) { - case OP_NOP: - case OP_RETURN_VOID: - case OP_GOTO: - case OP_GOTO_16: - case OP_GOTO_32: - /* no registers are used */ - break; - - case OP_RETURN: - case OP_RETURN_OBJECT: - case OP_MONITOR_ENTER: - case OP_MONITOR_EXIT: - case OP_CHECK_CAST: - case OP_THROW: - case OP_PACKED_SWITCH: - case OP_SPARSE_SWITCH: - case OP_FILL_ARRAY_DATA: - case OP_IF_EQZ: - case OP_IF_NEZ: - case OP_IF_LTZ: - case OP_IF_GEZ: - case OP_IF_GTZ: - case OP_IF_LEZ: - case OP_SPUT: - case OP_SPUT_BOOLEAN: - case OP_SPUT_BYTE: - case OP_SPUT_CHAR: - case OP_SPUT_SHORT: - case OP_SPUT_OBJECT: - /* action <- vA */ - GEN(workBits, decInsn.vA); - break; - - case OP_RETURN_WIDE: - case OP_SPUT_WIDE: - /* action <- vA(wide) */ - GENW(workBits, decInsn.vA); - break; - - case OP_IF_EQ: - case OP_IF_NE: - case OP_IF_LT: - case OP_IF_GE: - case OP_IF_GT: - case OP_IF_LE: - case OP_IPUT: - case OP_IPUT_BOOLEAN: - case OP_IPUT_BYTE: - case OP_IPUT_CHAR: - case OP_IPUT_SHORT: - case OP_IPUT_OBJECT: - /* action <- vA, vB */ - GEN(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - break; - - case OP_IPUT_WIDE: - /* action <- vA(wide), vB */ - GENW(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - break; - - case OP_APUT: - case OP_APUT_BOOLEAN: - case OP_APUT_BYTE: - case OP_APUT_CHAR: - case OP_APUT_SHORT: - case OP_APUT_OBJECT: - /* action <- vA, vB, vC */ - GEN(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - GEN(workBits, decInsn.vC); - break; - - case OP_APUT_WIDE: - /* action <- vA(wide), vB, vC */ - GENW(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - GEN(workBits, decInsn.vC); - break; - - case OP_FILLED_NEW_ARRAY: - case OP_INVOKE_VIRTUAL: - case OP_INVOKE_SUPER: - case OP_INVOKE_DIRECT: - case OP_INVOKE_STATIC: - case OP_INVOKE_INTERFACE: - /* action <- vararg */ - { - unsigned int idx; - for (idx = 0; idx < decInsn.vA; idx++) { - GEN(workBits, decInsn.arg[idx]); - } - } - break; - - case OP_FILLED_NEW_ARRAY_RANGE: - case OP_INVOKE_VIRTUAL_RANGE: - case OP_INVOKE_SUPER_RANGE: - case OP_INVOKE_DIRECT_RANGE: - case OP_INVOKE_STATIC_RANGE: - case OP_INVOKE_INTERFACE_RANGE: - /* action <- vararg/range */ - { - unsigned int idx; - for (idx = 0; idx < decInsn.vA; idx++) { - GEN(workBits, decInsn.vC + idx); - } - } - break; - - case OP_MOVE_RESULT: - case OP_MOVE_RESULT_WIDE: - case OP_MOVE_RESULT_OBJECT: - case OP_MOVE_EXCEPTION: - case OP_CONST_4: - case OP_CONST_16: - case OP_CONST: - case OP_CONST_HIGH16: - case OP_CONST_STRING: - case OP_CONST_STRING_JUMBO: - case OP_CONST_CLASS: - case OP_NEW_INSTANCE: - case OP_SGET: - case OP_SGET_BOOLEAN: - case OP_SGET_BYTE: - case OP_SGET_CHAR: - case OP_SGET_SHORT: - case OP_SGET_OBJECT: - /* vA <- value */ - KILL(workBits, decInsn.vA); - break; - - case OP_CONST_WIDE_16: - case OP_CONST_WIDE_32: - case OP_CONST_WIDE: - case OP_CONST_WIDE_HIGH16: - case OP_SGET_WIDE: - /* vA(wide) <- value */ - KILLW(workBits, decInsn.vA); - break; - - case OP_MOVE: - case OP_MOVE_FROM16: - case OP_MOVE_16: - case OP_MOVE_OBJECT: - case OP_MOVE_OBJECT_FROM16: - case OP_MOVE_OBJECT_16: - case OP_INSTANCE_OF: - case OP_ARRAY_LENGTH: - case OP_NEW_ARRAY: - case OP_IGET: - case OP_IGET_BOOLEAN: - case OP_IGET_BYTE: - case OP_IGET_CHAR: - case OP_IGET_SHORT: - case OP_IGET_OBJECT: - case OP_NEG_INT: - case OP_NOT_INT: - case OP_NEG_FLOAT: - case OP_INT_TO_FLOAT: - case OP_FLOAT_TO_INT: - case OP_INT_TO_BYTE: - case OP_INT_TO_CHAR: - case OP_INT_TO_SHORT: - case OP_ADD_INT_LIT16: - case OP_RSUB_INT: - case OP_MUL_INT_LIT16: - case OP_DIV_INT_LIT16: - case OP_REM_INT_LIT16: - case OP_AND_INT_LIT16: - case OP_OR_INT_LIT16: - case OP_XOR_INT_LIT16: - case OP_ADD_INT_LIT8: - case OP_RSUB_INT_LIT8: - case OP_MUL_INT_LIT8: - case OP_DIV_INT_LIT8: - case OP_REM_INT_LIT8: - case OP_SHL_INT_LIT8: - case OP_SHR_INT_LIT8: - case OP_USHR_INT_LIT8: - case OP_AND_INT_LIT8: - case OP_OR_INT_LIT8: - case OP_XOR_INT_LIT8: - /* vA <- vB */ - KILL(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - break; - - case OP_IGET_WIDE: - case OP_INT_TO_LONG: - case OP_INT_TO_DOUBLE: - case OP_FLOAT_TO_LONG: - case OP_FLOAT_TO_DOUBLE: - /* vA(wide) <- vB */ - KILLW(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - break; - - case OP_LONG_TO_INT: - case OP_LONG_TO_FLOAT: - case OP_DOUBLE_TO_INT: - case OP_DOUBLE_TO_FLOAT: - /* vA <- vB(wide) */ - KILL(workBits, decInsn.vA); - GENW(workBits, decInsn.vB); - break; - - case OP_MOVE_WIDE: - case OP_MOVE_WIDE_FROM16: - case OP_MOVE_WIDE_16: - case OP_NEG_LONG: - case OP_NOT_LONG: - case OP_NEG_DOUBLE: - case OP_LONG_TO_DOUBLE: - case OP_DOUBLE_TO_LONG: - /* vA(wide) <- vB(wide) */ - KILLW(workBits, decInsn.vA); - GENW(workBits, decInsn.vB); - break; - - case OP_CMPL_FLOAT: - case OP_CMPG_FLOAT: - case OP_AGET: - case OP_AGET_BOOLEAN: - case OP_AGET_BYTE: - case OP_AGET_CHAR: - case OP_AGET_SHORT: - case OP_AGET_OBJECT: - case OP_ADD_INT: - case OP_SUB_INT: - case OP_MUL_INT: - case OP_REM_INT: - case OP_DIV_INT: - case OP_AND_INT: - case OP_OR_INT: - case OP_XOR_INT: - case OP_SHL_INT: - case OP_SHR_INT: - case OP_USHR_INT: - case OP_ADD_FLOAT: - case OP_SUB_FLOAT: - case OP_MUL_FLOAT: - case OP_DIV_FLOAT: - case OP_REM_FLOAT: - /* vA <- vB, vC */ - KILL(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - GEN(workBits, decInsn.vC); - break; - - case OP_AGET_WIDE: - /* vA(wide) <- vB, vC */ - KILLW(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - GEN(workBits, decInsn.vC); - break; - - case OP_CMPL_DOUBLE: - case OP_CMPG_DOUBLE: - case OP_CMP_LONG: - /* vA <- vB(wide), vC(wide) */ - KILL(workBits, decInsn.vA); - GENW(workBits, decInsn.vB); - GENW(workBits, decInsn.vC); - break; - - case OP_SHL_LONG: - case OP_SHR_LONG: - case OP_USHR_LONG: - /* vA(wide) <- vB(wide), vC */ - KILLW(workBits, decInsn.vA); - GENW(workBits, decInsn.vB); - GEN(workBits, decInsn.vC); - break; - - case OP_ADD_LONG: - case OP_SUB_LONG: - case OP_MUL_LONG: - case OP_DIV_LONG: - case OP_REM_LONG: - case OP_AND_LONG: - case OP_OR_LONG: - case OP_XOR_LONG: - case OP_ADD_DOUBLE: - case OP_SUB_DOUBLE: - case OP_MUL_DOUBLE: - case OP_DIV_DOUBLE: - case OP_REM_DOUBLE: - /* vA(wide) <- vB(wide), vC(wide) */ - KILLW(workBits, decInsn.vA); - GENW(workBits, decInsn.vB); - GENW(workBits, decInsn.vC); - break; - - case OP_ADD_INT_2ADDR: - case OP_SUB_INT_2ADDR: - case OP_MUL_INT_2ADDR: - case OP_REM_INT_2ADDR: - case OP_SHL_INT_2ADDR: - case OP_SHR_INT_2ADDR: - case OP_USHR_INT_2ADDR: - case OP_AND_INT_2ADDR: - case OP_OR_INT_2ADDR: - case OP_XOR_INT_2ADDR: - case OP_DIV_INT_2ADDR: - /* vA <- vA, vB */ - /* KILL(workBits, decInsn.vA); */ - GEN(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - break; - - case OP_SHL_LONG_2ADDR: - case OP_SHR_LONG_2ADDR: - case OP_USHR_LONG_2ADDR: - /* vA(wide) <- vA(wide), vB */ - /* KILLW(workBits, decInsn.vA); */ - GENW(workBits, decInsn.vA); - GEN(workBits, decInsn.vB); - break; - - case OP_ADD_LONG_2ADDR: - case OP_SUB_LONG_2ADDR: - case OP_MUL_LONG_2ADDR: - case OP_DIV_LONG_2ADDR: - case OP_REM_LONG_2ADDR: - case OP_AND_LONG_2ADDR: - case OP_OR_LONG_2ADDR: - case OP_XOR_LONG_2ADDR: - case OP_ADD_FLOAT_2ADDR: - case OP_SUB_FLOAT_2ADDR: - case OP_MUL_FLOAT_2ADDR: - case OP_DIV_FLOAT_2ADDR: - case OP_REM_FLOAT_2ADDR: - case OP_ADD_DOUBLE_2ADDR: - case OP_SUB_DOUBLE_2ADDR: - case OP_MUL_DOUBLE_2ADDR: - case OP_DIV_DOUBLE_2ADDR: - case OP_REM_DOUBLE_2ADDR: - /* vA(wide) <- vA(wide), vB(wide) */ - /* KILLW(workBits, decInsn.vA); */ - GENW(workBits, decInsn.vA); - GENW(workBits, decInsn.vB); - break; - - /* we will only see this if liveness analysis is done after general vfy */ - case OP_THROW_VERIFICATION_ERROR: - /* no registers used */ - break; - - /* quickened instructions, not expected to appear */ - case OP_EXECUTE_INLINE: - case OP_EXECUTE_INLINE_RANGE: - case OP_IGET_QUICK: - case OP_IGET_WIDE_QUICK: - case OP_IGET_OBJECT_QUICK: - case OP_IPUT_QUICK: - case OP_IPUT_WIDE_QUICK: - case OP_IPUT_OBJECT_QUICK: - case OP_INVOKE_VIRTUAL_QUICK: - case OP_INVOKE_VIRTUAL_QUICK_RANGE: - case OP_INVOKE_SUPER_QUICK: - case OP_INVOKE_SUPER_QUICK_RANGE: - /* fall through to failure */ - - /* correctness fixes, not expected to appear */ - case OP_INVOKE_OBJECT_INIT_RANGE: - case OP_RETURN_VOID_BARRIER: - case OP_SPUT_VOLATILE: - case OP_SPUT_OBJECT_VOLATILE: - case OP_SPUT_WIDE_VOLATILE: - case OP_IPUT_VOLATILE: - case OP_IPUT_OBJECT_VOLATILE: - case OP_IPUT_WIDE_VOLATILE: - case OP_SGET_VOLATILE: - case OP_SGET_OBJECT_VOLATILE: - case OP_SGET_WIDE_VOLATILE: - case OP_IGET_VOLATILE: - case OP_IGET_OBJECT_VOLATILE: - case OP_IGET_WIDE_VOLATILE: - /* fall through to failure */ - - /* these should never appear during verification */ - case OP_UNUSED_3E: - case OP_UNUSED_3F: - case OP_UNUSED_40: - case OP_UNUSED_41: - case OP_UNUSED_42: - case OP_UNUSED_43: - case OP_UNUSED_73: - case OP_UNUSED_79: - case OP_UNUSED_7A: - case OP_BREAKPOINT: - case OP_UNUSED_FF: - return false; - } - - return true; -} - -/* - * This is a dexDecodeDebugInfo callback, used by markDebugLocals(). - */ -static void markLocalsCb(void* ctxt, u2 reg, u4 startAddress, u4 endAddress, - const char* name, const char* descriptor, const char* signature) -{ - VerifierData* vdata = (VerifierData*) ctxt; - bool verbose = dvmWantVerboseVerification(vdata->method); - - if (verbose) { - ALOGI("%04x-%04x %2d (%s %s)", - startAddress, endAddress, reg, name, descriptor); - } - - bool wide = (descriptor[0] == 'D' || descriptor[0] == 'J'); - assert(reg <= vdata->insnRegCount + (wide ? 1 : 0)); - - /* - * Set the bit in all GC point instructions in the range - * [startAddress, endAddress). - */ - unsigned int idx; - for (idx = startAddress; idx < endAddress; idx++) { - BitVector* liveRegs = vdata->registerLines[idx].liveRegs; - if (liveRegs != NULL) { - if (wide) { - GENW(liveRegs, reg); - } else { - GEN(liveRegs, reg); - } - } - } -} - -/* - * Mark all debugger-visible locals as live. - * - * The "locals" table describes the positions of the various locals in the - * stack frame based on the current execution address. If the debugger - * wants to display one, it issues a request by "slot number". We need - * to ensure that references in stack slots that might be queried by the - * debugger aren't GCed. - * - * (If the GC had some way to mark the slot as invalid we wouldn't have - * to do this. We could also have the debugger interface check the - * register map and simply refuse to return a "dead" value, but that's - * potentially confusing since the referred-to object might actually be - * alive, and being able to see it without having to hunt around for a - * "live" stack frame is useful.) - */ -static bool markDebugLocals(VerifierData* vdata) -{ - const Method* meth = vdata->method; - - dexDecodeDebugInfo(meth->clazz->pDvmDex->pDexFile, dvmGetMethodCode(meth), - meth->clazz->descriptor, meth->prototype.protoIdx, meth->accessFlags, - NULL, markLocalsCb, vdata); - - return true; -} - - -/* - * Dump the liveness bits to the log. - * - * "curIdx" is for display only. - */ -static void dumpLiveState(const VerifierData* vdata, u4 curIdx, - const BitVector* workBits) -{ - u4 insnRegCount = vdata->insnRegCount; - size_t regCharSize = insnRegCount + (insnRegCount-1)/4 + 2 +1; - char regChars[regCharSize +1]; - unsigned int idx; - - memset(regChars, ' ', regCharSize); - regChars[0] = '['; - if (insnRegCount == 0) - regChars[1] = ']'; - else - regChars[1 + (insnRegCount-1) + (insnRegCount-1)/4 +1] = ']'; - regChars[regCharSize] = '\0'; - - for (idx = 0; idx < insnRegCount; idx++) { - char ch = dvmIsBitSet(workBits, idx) ? '+' : '-'; - regChars[1 + idx + (idx/4)] = ch; - } - - ALOGI("0x%04x %s", curIdx, regChars); -} |