while (callerIter.hasNext()) { int caller = ((Integer) callerIter.next()).intValue(); int returnLoc = getNext(iter, caller, pos); boolean changed = false;
mergeTableSwitch(queue, pos, iter, frame); } else if (opcode == LOOKUPSWITCH) { mergeLookupSwitch(queue, pos, iter, frame); } else if (opcode == RET) { mergeRet(queue, iter, pos, frame, subroutine); } else if (Util.isJumpInstruction(opcode)) { int target = Util.getJumpTarget(pos, iter); mergeJsr(queue, frames[pos], subroutines[target], pos, lookAhead(iter, pos)); } else if (! Util.isGoto(opcode)) { merge(queue, frame, lookAhead(iter, pos)); merge(queue, frame, target); } else if (opcode != ATHROW && ! Util.isReturn(opcode)) { merge(queue, frame, lookAhead(iter, pos)); mergeExceptionHandlers(queue, method, pos, frame);
IntQueue queue = new IntQueue(); exceptions = buildExceptionInfo(method); subroutines = scanner.scan(method); frames[iter.lookAhead()] = firstFrame(method, maxLocals, maxStack); queue.add(iter.next()); while (!queue.isEmpty()) { analyzeNextEntry(method, iter, queue, executor);
private void mergeLookupSwitch(IntQueue queue, int pos, CodeIterator iter, Frame frame) throws BadBytecode { int index = (pos & ~3) + 4; // default merge(queue, frame, pos + iter.s32bitAt(index)); int npairs = iter.s32bitAt(index += 4); int end = npairs * 8 + (index += 4); // skip "match" for (index += 4; index < end; index += 8) { int target = iter.s32bitAt(index) + pos; merge(queue, frame, target); } }
/** * Performs data-flow analysis on a method and returns an array, indexed by * instruction position, containing the starting frame state of all reachable * instructions. Non-reachable code, and illegal code offsets are represented * as a null in the frame state array. This can be used to detect dead code. * * If the method does not contain code (it is either native or abstract), null * is returned. * * @param method the method to analyze * @return an array, indexed by instruction position, of the starting frame state, * or null if this method doesn't have code * @throws BadBytecode if the bytecode does not comply with the JVM specification */ public Frame[] analyze(CtMethod method) throws BadBytecode { return analyze(method.getDeclaringClass(), method.getMethodInfo2()); }
IntQueue queue = new IntQueue(); exceptions = buildExceptionInfo(method); subroutines = scanner.scan(method); frames[iter.lookAhead()] = firstFrame(method, maxLocals, maxStack); queue.add(iter.next()); while (!queue.isEmpty()) { analyzeNextEntry(method, iter, queue, executor);
private void mergeTableSwitch(IntQueue queue, int pos, CodeIterator iter, Frame frame) throws BadBytecode { // Skip 4 byte alignment padding int index = (pos & ~3) + 4; // default merge(queue, frame, pos + iter.s32bitAt(index)); int low = iter.s32bitAt(index += 4); int high = iter.s32bitAt(index += 4); int end = (high - low + 1) * 4 + (index += 4); // Offset table for (; index < end; index += 4) { int target = iter.s32bitAt(index) + pos; merge(queue, frame, target); } }
/** * Performs data-flow analysis on a method and returns an array, indexed by * instruction position, containing the starting frame state of all reachable * instructions. Non-reachable code, and illegal code offsets are represented * as a null in the frame state array. This can be used to detect dead code. * * If the method does not contain code (it is either native or abstract), null * is returned. * * @param method the method to analyze * @return an array, indexed by instruction position, of the starting frame state, * or null if this method doesn't have code * @throws BadBytecode if the bytecode does not comply with the JVM specification */ public Frame[] analyze(CtMethod method) throws BadBytecode { return analyze(method.getDeclaringClass(), method.getMethodInfo2()); }
mergeTableSwitch(queue, pos, iter, frame); } else if (opcode == LOOKUPSWITCH) { mergeLookupSwitch(queue, pos, iter, frame); } else if (opcode == RET) { mergeRet(queue, iter, pos, frame, subroutine); } else if (Util.isJumpInstruction(opcode)) { int target = Util.getJumpTarget(pos, iter); mergeJsr(queue, frames[pos], subroutines[target], pos, lookAhead(iter, pos)); } else if (! Util.isGoto(opcode)) { merge(queue, frame, lookAhead(iter, pos)); merge(queue, frame, target); } else if (opcode != ATHROW && ! Util.isReturn(opcode)) { merge(queue, frame, lookAhead(iter, pos)); mergeExceptionHandlers(queue, method, pos, frame);
/** * Returns the types of the local variables and stack frame entries * available at the given position. If the byte at the position is * not the first byte of an instruction, then this method returns * null. * * @param pos the position. */ public Frame frameAt(int pos) throws BadBytecode { if (frames == null) frames = new Analyzer().analyze(clazz, methodInfo); return frames[pos]; }
IntQueue queue = new IntQueue(); exceptions = buildExceptionInfo(method); subroutines = scanner.scan(method); frames[iter.lookAhead()] = firstFrame(method, maxLocals, maxStack); queue.add(iter.next()); while (!queue.isEmpty()) { analyzeNextEntry(method, iter, queue, executor);
private void mergeLookupSwitch(IntQueue queue, int pos, CodeIterator iter, Frame frame) throws BadBytecode { int index = (pos & ~3) + 4; // default merge(queue, frame, pos + iter.s32bitAt(index)); int npairs = iter.s32bitAt(index += 4); int end = npairs * 8 + (index += 4); // skip "match" for (index += 4; index < end; index += 8) { int target = iter.s32bitAt(index) + pos; merge(queue, frame, target); } }
/** * Performs data-flow analysis on a method and returns an array, indexed by * instruction position, containing the starting frame state of all reachable * instructions. Non-reachable code, and illegal code offsets are represented * as a null in the frame state array. This can be used to detect dead code. * * If the method does not contain code (it is either native or abstract), null * is returned. * * @param method the method to analyze * @return an array, indexed by instruction position, of the starting frame state, * or null if this method doesn't have code * @throws BadBytecode if the bytecode does not comply with the JVM specification */ public Frame[] analyze(CtMethod method) throws BadBytecode { return analyze(method.getDeclaringClass(), method.getMethodInfo2()); }
private void mergeRet(IntQueue queue, CodeIterator iter, int pos, Frame frame, Subroutine subroutine) throws BadBytecode { if (subroutine == null) throw new BadBytecode("Ret on no subroutine! [pos = " + pos + "]"); for (int caller:subroutine.callers()) { int returnLoc = getNext(iter, caller, pos); boolean changed = false; Frame old = frames[returnLoc]; if (old == null) { old = frames[returnLoc] = frame.copyStack(); changed = true; } else { changed = old.mergeStack(frame); } for (int index:subroutine.accessed()) { Type oldType = old.getLocal(index); Type newType = frame.getLocal(index); if (oldType != newType) { old.setLocal(index, newType); changed = true; } } if (! old.isRetMerged()) { old.setRetMerged(true); changed = true; } if (changed && old.isJsrMerged()) queue.add(returnLoc); } }
mergeTableSwitch(queue, pos, iter, frame); } else if (opcode == LOOKUPSWITCH) { mergeLookupSwitch(queue, pos, iter, frame); } else if (opcode == RET) { mergeRet(queue, iter, pos, frame, subroutine); } else if (Util.isJumpInstruction(opcode)) { int target = Util.getJumpTarget(pos, iter); mergeJsr(queue, frames[pos], subroutines[target], pos, lookAhead(iter, pos)); } else if (! Util.isGoto(opcode)) { merge(queue, frame, lookAhead(iter, pos)); merge(queue, frame, target); } else if (opcode != ATHROW && ! Util.isReturn(opcode)) { merge(queue, frame, lookAhead(iter, pos)); mergeExceptionHandlers(queue, method, pos, frame);
IntQueue queue = new IntQueue(); exceptions = buildExceptionInfo(method); subroutines = scanner.scan(method); frames[iter.lookAhead()] = firstFrame(method, maxLocals, maxStack); queue.add(iter.next()); while (!queue.isEmpty()) { analyzeNextEntry(method, iter, queue, executor);
private void mergeExceptionHandlers(IntQueue queue, MethodInfo method, int pos, Frame frame) { for (int i = 0; i < exceptions.length; i++) { ExceptionInfo exception = exceptions[i]; // Start is inclusive, while end is exclusive! if (pos >= exception.start && pos < exception.end) { Frame newFrame = frame.copy(); newFrame.clearStack(); newFrame.push(exception.type); merge(queue, newFrame, exception.handler); } } }
/** * Performs data-flow analysis on a method and returns an array, indexed by * instruction position, containing the starting frame state of all reachable * instructions. Non-reachable code, and illegal code offsets are represented * as a null in the frame state array. This can be used to detect dead code. * * If the method does not contain code (it is either native or abstract), null * is returned. * * @param method the method to analyze * @return an array, indexed by instruction position, of the starting frame state, * or null if this method doesn't have code * @throws BadBytecode if the bytecode does not comply with the JVM specification */ public Frame[] analyze(CtMethod method) throws BadBytecode { return analyze(method.getDeclaringClass(), method.getMethodInfo2()); }