private void merge( final int insn, final Frame beforeJSR, final Frame afterRET, final Subroutine subroutineBeforeJSR, final boolean[] access) throws AnalyzerException { Frame oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes; afterRET.merge(beforeJSR, access); if (oldFrame == null) { frames[insn] = newFrame(afterRET); changes = true; } else { changes = oldFrame.merge(afterRET, access); } if (oldSubroutine != null && subroutineBeforeJSR != null) { changes |= oldSubroutine.merge(subroutineBeforeJSR); } if (changes && !queued[insn]) { queued[insn] = true; queue[top++] = insn; } }
private void merge(final int insn, final Frame frame, final Subroutine subroutine) throws AnalyzerException { if (insn > n - 1) { throw new AnalyzerException("Execution can fall off end of the code"); } else { Frame oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes = false; if (oldFrame == null) { frames[insn] = newFrame(frame); changes = true; } else { changes |= oldFrame.merge(frame, interpreter); } newControlFlowEdge(frame, oldFrame); if (oldSubroutine == null) { if (subroutine != null) { subroutines[insn] = subroutine.copy(); changes = true; } } else { if (subroutine != null) { changes |= oldSubroutine.merge(subroutine, !jsr); } } if (changes && !queued[insn]) { queued[insn] = true; queue[top++] = insn; } } }
private void merge(final int insn, final Frame frame, final Subroutine subroutine) throws AnalyzerException { Frame oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes; if (oldFrame == null) { frames[insn] = newFrame(frame); changes = true; } else { changes = oldFrame.merge(frame, interpreter); } if (oldSubroutine == null) { if (subroutine != null) { subroutines[insn] = subroutine.copy(); changes = true; } } else { if (subroutine != null) { changes |= oldSubroutine.merge(subroutine); } } if (changes && !queued[insn]) { queued[insn] = true; queue[top++] = insn; } }
public static LispObject evaluate(String name, Environment environment, List<LispObject> args) { for (Class c : getSubroutineContainers()) { for (Method m : c.getMethods()) { Subroutine annotation = m.getAnnotation(Subroutine.class); if (annotation == null || !annotation.value().equals(name)) continue; if (!Arrays.asList(mySpecialForms).contains(c)) { if (!environment.areArgumentsEvaluated()) { for (int i = 0, dataSize = args.size(); i < dataSize; i++) { args.set(i, args.get(i).evaluate(environment)); } } else { environment.setArgumentsEvaluated(false); } } ArgumentsList arguments = parseArguments(m, environment, args); checkArguments(name, arguments, args); try { return (LispObject) m.invoke(null, arguments.getValues()); } catch (IllegalAccessException | InvocationTargetException e) { if (e.getCause().getMessage() == null) e.getCause().printStackTrace(); else System.err.println(e.getCause().getMessage()); Throwable cause = getCause(e); if (cause instanceof LispThrow) throw (LispThrow) cause; if (cause instanceof VoidVariableException && TestMode.TEST && c == Key.class) { System.err.println("Skip keymap errors in test mode"); return LispSymbol.ourNil; } if (cause instanceof LispException) throw (LispException) cause; cause.printStackTrace(); throw new LispException(e.getCause().getMessage()); } } } throw new InternalException(JelispBundle.message("unknown.subroutine", name)); }
public Subroutine copy() { Subroutine result = new Subroutine(); result.start = start; result.access = new boolean[access.length]; System.arraycopy(access, 0, result.access, 0, access.length); result.callers = new ArrayList(callers); return result; }
/** * Returns the subroutine object associated with the given instruction. This is a costly * operation, you should consider using getSubroutine(InstructionHandle). Returns 'null' if the * given InstructionHandle lies in so-called 'dead code', i.e. code that can never be executed. * * @see #getSubroutine(InstructionHandle) * @see #getTopLevel() */ public Subroutine subroutineOf(InstructionHandle any) { Iterator i = subroutines.values().iterator(); while (i.hasNext()) { Subroutine s = (Subroutine) i.next(); if (s.contains(any)) return s; } System.err.println("DEBUG: Please verify '" + any + "' lies in dead code."); return null; // throw new AssertionViolatedException("No subroutine for InstructionHandle found (DEAD // CODE?)."); }
private boolean scanOp( int pos, org.hotswap.agent.javassist.bytecode.CodeIterator iter, Subroutine sub) throws BadBytecode { subroutines[pos] = sub; int opcode = iter.byteAt(pos); if (opcode == TABLESWITCH) { scanTableSwitch(pos, iter, sub); return false; } if (opcode == LOOKUPSWITCH) { scanLookupSwitch(pos, iter, sub); return false; } // All forms of return and throw end current code flow if (Util.isReturn(opcode) || opcode == RET || opcode == ATHROW) { return false; } if (Util.isJumpInstruction(opcode)) { int target = Util.getJumpTarget(pos, iter); if (opcode == JSR || opcode == JSR_W) { Subroutine s = subTable.get(new Integer(target)); if (s == null) { s = new Subroutine(target, pos); subTable.put(new Integer(target), s); scan(target, iter, s); } else { s.addCaller(pos); } } else { scan(target, iter, sub); // GOTO ends current code flow if (Util.isGoto(opcode)) { return false; } } } return true; }
private void merge( final int insn, final Frame beforeJSR, final Frame afterRET, final Subroutine subroutineBeforeJSR, final boolean[] access) throws AnalyzerException { if (insn > n - 1) { throw new AnalyzerException("Execution can fall off end of the code"); } else { Frame oldFrame = frames[insn]; Subroutine oldSubroutine = subroutines[insn]; boolean changes = false; afterRET.merge(beforeJSR, access); if (oldFrame == null) { frames[insn] = newFrame(afterRET); changes = true; } else { changes |= oldFrame.merge(afterRET, access); } newControlFlowEdge(afterRET, oldFrame); if (oldSubroutine == null) { if (subroutineBeforeJSR != null) { subroutines[insn] = subroutineBeforeJSR.copy(); changes = true; } } else { if (subroutineBeforeJSR != null) { changes |= oldSubroutine.merge(subroutineBeforeJSR, !jsr); } } if (changes && !queued[insn]) { queued[insn] = true; queue[top++] = insn; } } }
@Override public void analyze(Log log, SymbolTable outer, Subroutine owner, boolean inLoop) { List<Subroutine> subroutines = getSubroutines(); // Create the table if it hasn't already been created. For blocks that are bodies of // functions or loops, the analyze() method of the function or loop will have created this // table already, since it is the table in which the parameters or loop indices belong. // For blocks that are entire scripts, the table will have already been created, too. // All other blocks will need their tables created here. if (table == null) { table = new SymbolTable(outer); } // Insert the routines into the table, but analyze ONLY the parameters and return types. // We can't analyze the function bodies until all the functions have been put into the // table (with analyzed parameters) because within any function body there can be a call // to any other function, and we have to be able to analyze the call. Notice also that the // functions are going in before any variables are being looked at since variables can call // any function in their initializing expressions. for (Subroutine subroutine : subroutines) { subroutine.analyzeSignature(log, table, owner, inLoop); table.insert(subroutine, log); } // Now just go through all the items in order and analyze everything, making sure to // insert variables because they have not yet been inserted. for (Statement s : statements) { if (s instanceof DecStatement) { DecStatement d = (DecStatement) s; for (String t : d.getNames()) { table.insert(new Variable(t), log); } } s.analyze(log, table, owner, inLoop); } }
/** * This (recursive) utility method makes sure that no subroutine is calling a subroutine that uses * the same local variable for the RET as themselves (recursively). This includes that subroutines * may not call themselves recursively, even not through intermediate calls to other subroutines. * * @throws StructuralCodeConstraintException if the above constraint is not satisfied. */ private void noRecursiveCalls(Subroutine sub, HashSet<Integer> set) { Subroutine[] subs = sub.subSubs(); for (int i = 0; i < subs.length; i++) { int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex(); if (!set.add(new Integer(index))) { // Don't use toString() here because of possibly infinite recursive subSubs() calls then. SubroutineImpl si = (SubroutineImpl) subs[i]; throw new StructuralCodeConstraintException( "Subroutine with local variable '" + si.localVariable + "', JSRs '" + si.theJSRs + "', RET '" + si.theRET + "' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both."); } noRecursiveCalls(subs[i], set); set.remove(new Integer(index)); } }
/** * Analyzes the given method. * * @param c the class to which the method belongs. * @param m the method to be analyzed. * @return the symbolic state of the execution stack frame at each bytecode instruction of the * method. The size of the returned array is equal to the number of instructions (and labels) * of the method. A given frame is <tt>null</tt> if and only if the corresponding instruction * cannot be reached (dead code). * @throws AnalyzerException if a problem occurs during the analysis. */ public Frame[] analyze(final ClassNode c, final MethodNode m) throws AnalyzerException { n = m.instructions.size(); indexes = new IntMap(2 * n); handlers = new List[n]; frames = new Frame[n]; subroutines = new Subroutine[n]; queued = new boolean[n]; queue = new int[n]; top = 0; // computes instruction indexes for (int i = 0; i < n; ++i) { indexes.put(m.instructions.get(i), i); } // computes exception handlers for each instruction for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i); int begin = indexes.get(tcb.start); int end = indexes.get(tcb.end); for (int j = begin; j < end; ++j) { List insnHandlers = handlers[j]; if (insnHandlers == null) { insnHandlers = new ArrayList(); handlers[j] = insnHandlers; } insnHandlers.add(tcb); } } // initializes the data structures for the control flow analysis algorithm Frame current = newFrame(m.maxLocals, m.maxStack); Frame handler = newFrame(m.maxLocals, m.maxStack); Type[] args = Type.getArgumentTypes(m.desc); int local = 0; if ((m.access & ACC_STATIC) == 0) { Type ctype = Type.getType("L" + c.name + ";"); current.setLocal(local++, interpreter.newValue(ctype)); } for (int i = 0; i < args.length; ++i) { current.setLocal(local++, interpreter.newValue(args[i])); if (args[i].getSize() == 2) { current.setLocal(local++, interpreter.newValue(null)); } } while (local < m.maxLocals) { current.setLocal(local++, interpreter.newValue(null)); } merge(0, current, null); // control flow analysis while (top > 0) { int insn = queue[--top]; Frame f = frames[insn]; Subroutine subroutine = subroutines[insn]; queued[insn] = false; try { Object o = m.instructions.get(insn); jsr = false; if (o instanceof Label) { merge(insn + 1, f, subroutine); } else { AbstractInsnNode insnNode = (AbstractInsnNode) o; int insnOpcode = insnNode.getOpcode(); current.init(f).execute(insnNode, interpreter); subroutine = subroutine == null ? null : subroutine.copy(); if (insnNode instanceof JumpInsnNode) { JumpInsnNode j = (JumpInsnNode) insnNode; if (insnOpcode != GOTO && insnOpcode != JSR) { merge(insn + 1, current, subroutine); } if (insnOpcode == JSR) { jsr = true; merge(indexes.get(j.label), current, new Subroutine(j.label, m.maxLocals, j)); } else { merge(indexes.get(j.label), current, subroutine); } } else if (insnNode instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; merge(indexes.get(lsi.dflt), current, subroutine); for (int j = 0; j < lsi.labels.size(); ++j) { Label label = (Label) lsi.labels.get(j); merge(indexes.get(label), current, subroutine); } } else if (insnNode instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; merge(indexes.get(tsi.dflt), current, subroutine); for (int j = 0; j < tsi.labels.size(); ++j) { Label label = (Label) tsi.labels.get(j); merge(indexes.get(label), current, subroutine); } } else if (insnOpcode == RET) { if (subroutine == null) { throw new AnalyzerException("RET instruction outside of a sub routine"); } else { for (int i = 0; i < subroutine.callers.size(); ++i) { int caller = indexes.get(subroutine.callers.get(i)); merge(caller + 1, frames[caller], current, subroutines[caller], subroutine.access); } } } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) { if (subroutine != null) { if (insnNode instanceof VarInsnNode) { int var = ((VarInsnNode) insnNode).var; subroutine.access[var] = true; if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE || insnOpcode == DSTORE) { subroutine.access[var + 1] = true; } } else if (insnNode instanceof IincInsnNode) { int var = ((IincInsnNode) insnNode).var; subroutine.access[var] = true; } } merge(insn + 1, current, subroutine); } } List insnHandlers = handlers[insn]; if (insnHandlers != null) { for (int i = 0; i < insnHandlers.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); Type type; if (tcb.type == null) { type = Type.getType("Ljava/lang/Throwable;"); } else { type = Type.getType("L" + tcb.type + ";"); } handler.init(f); handler.clearStack(); handler.push(interpreter.newValue(type)); merge(indexes.get(tcb.handler), handler, subroutine); } } } catch (Exception e) { throw new AnalyzerException("Error at instruction " + insn + ": " + e.getMessage()); } } return frames; }
/** * Constructor. * * @param il A MethodGen object representing method to create the Subroutine objects of. */ public Subroutines(MethodGen mg) { InstructionHandle[] all = mg.getInstructionList().getInstructionHandles(); CodeExceptionGen[] handlers = mg.getExceptionHandlers(); // Define our "Toplevel" fake subroutine. TOPLEVEL = new SubroutineImpl(); // Calculate "real" subroutines. HashSet<InstructionHandle> sub_leaders = new HashSet<InstructionHandle>(); // Elements: InstructionHandle for (int i = 0; i < all.length; i++) { Instruction inst = all[i].getInstruction(); if (inst instanceof JsrInstruction) { sub_leaders.add(((JsrInstruction) inst).getTarget()); } } // Build up the database. Iterator iter = sub_leaders.iterator(); while (iter.hasNext()) { SubroutineImpl sr = new SubroutineImpl(); InstructionHandle astore = (InstructionHandle) (iter.next()); sr.setLocalVariable(((ASTORE) (astore.getInstruction())).getIndex()); subroutines.put(astore, sr); } // Fake it a bit. We want a virtual "TopLevel" subroutine. subroutines.put(all[0], TOPLEVEL); sub_leaders.add(all[0]); // Tell the subroutines about their JsrInstructions. // Note that there cannot be a JSR targeting the top-level // since "Jsr 0" is disallowed in Pass 3a. // Instructions shared by a subroutine and the toplevel are // disallowed and checked below, after the BFS. for (int i = 0; i < all.length; i++) { Instruction inst = all[i].getInstruction(); if (inst instanceof JsrInstruction) { InstructionHandle leader = ((JsrInstruction) inst).getTarget(); ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]); } } // Now do a BFS from every subroutine leader to find all the // instructions that belong to a subroutine. HashSet<InstructionHandle> instructions_assigned = new HashSet<InstructionHandle>(); // we don't want to assign an instruction to two or more // Subroutine objects. Hashtable<InstructionHandle, Color> colors = new Hashtable< InstructionHandle, Color>(); // Graph colouring. Key: InstructionHandle, Value: java.awt.Color . iter = sub_leaders.iterator(); while (iter.hasNext()) { // Do some BFS with "actual" as the root of the graph. InstructionHandle actual = (InstructionHandle) (iter.next()); // Init colors for (int i = 0; i < all.length; i++) { colors.put(all[i], Color.white); } colors.put(actual, Color.gray); // Init Queue ArrayList<InstructionHandle> Q = new ArrayList<InstructionHandle>(); Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start. /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/ if (actual == all[0]) { for (int j = 0; j < handlers.length; j++) { colors.put(handlers[j].getHandlerPC(), Color.gray); Q.add(handlers[j].getHandlerPC()); } } /* CONTINUE NORMAL BFS ALGORITHM */ // Loop until Queue is empty while (Q.size() != 0) { InstructionHandle u = (InstructionHandle) Q.remove(0); InstructionHandle[] successors = getSuccessors(u); for (int i = 0; i < successors.length; i++) { if (((Color) colors.get(successors[i])) == Color.white) { colors.put(successors[i], Color.gray); Q.add(successors[i]); } } colors.put(u, Color.black); } // BFS ended above. for (int i = 0; i < all.length; i++) { if (colors.get(all[i]) == Color.black) { ((SubroutineImpl) (actual == all[0] ? getTopLevel() : getSubroutine(actual))) .addInstruction(all[i]); if (instructions_assigned.contains(all[i])) { throw new StructuralCodeConstraintException( "Instruction '" + all[i] + "' is part of more than one subroutine (or of the top level and a subroutine)."); } else { instructions_assigned.add(all[i]); } } } if (actual != all[0]) { // If we don't deal with the top-level 'subroutine' ((SubroutineImpl) getSubroutine(actual)).setLeavingRET(); } } // Now make sure no instruction of a Subroutine is protected by exception handling code // as is mandated by JustIces notion of subroutines. for (int i = 0; i < handlers.length; i++) { InstructionHandle _protected = handlers[i].getStartPC(); while (_protected != handlers[i] .getEndPC() .getNext()) { // Note the inclusive/inclusive notation of "generic API" exception // handlers! Enumeration subs = subroutines.elements(); while (subs.hasMoreElements()) { Subroutine sub = (Subroutine) subs.nextElement(); if (sub != subroutines.get(all[0])) { // We don't want to forbid top-level exception handlers. if (sub.contains(_protected)) { throw new StructuralCodeConstraintException( "Subroutine instruction '" + _protected + "' is protected by an exception handler, '" + handlers[i] + "'. This is forbidden by the JustIce verifier due to its clear definition of subroutines."); } } } _protected = _protected.getNext(); } } // Now make sure no subroutine is calling a subroutine // that uses the same local variable for the RET as themselves // (recursively). // This includes that subroutines may not call themselves // recursively, even not through intermediate calls to other // subroutines. noRecursiveCalls(getTopLevel(), new HashSet<Integer>()); }
/** * Analyzes the given method. * * @param owner the internal name of the class to which the method belongs. * @param m the method to be analyzed. * @return the symbolic state of the execution stack frame at each bytecode instruction of the * method. The size of the returned array is equal to the number of instructions (and labels) * of the method. A given frame is <tt>null</tt> if and only if the corresponding instruction * cannot be reached (dead code). * @throws AnalyzerException if a problem occurs during the analysis. */ public Frame[] analyze(final String owner, final MethodNode m) throws AnalyzerException { if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) { frames = new Frame[0]; return frames; } n = m.instructions.size(); insns = m.instructions; handlers = new List[n]; frames = new Frame[n]; subroutines = new Subroutine[n]; queued = new boolean[n]; queue = new int[n]; top = 0; // computes exception handlers for each instruction for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i); int begin = insns.indexOf(tcb.start); int end = insns.indexOf(tcb.end); for (int j = begin; j < end; ++j) { List insnHandlers = handlers[j]; if (insnHandlers == null) { insnHandlers = new ArrayList(); handlers[j] = insnHandlers; } insnHandlers.add(tcb); } } // computes the subroutine for each instruction: Subroutine main = new Subroutine(null, m.maxLocals, null); List subroutineCalls = new ArrayList(); Map subroutineHeads = new HashMap(); findSubroutine(0, main, subroutineCalls); while (!subroutineCalls.isEmpty()) { JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0); Subroutine sub = (Subroutine) subroutineHeads.get(jsr.label); if (sub == null) { sub = new Subroutine(jsr.label, m.maxLocals, jsr); subroutineHeads.put(jsr.label, sub); findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls); } else { sub.callers.add(jsr); } } for (int i = 0; i < n; ++i) { if (subroutines[i] != null && subroutines[i].start == null) { subroutines[i] = null; } } // initializes the data structures for the control flow analysis Frame current = newFrame(m.maxLocals, m.maxStack); Frame handler = newFrame(m.maxLocals, m.maxStack); Type[] args = Type.getArgumentTypes(m.desc); int local = 0; if ((m.access & ACC_STATIC) == 0) { Type ctype = Type.getObjectType(owner); current.setLocal(local++, interpreter.newValue(ctype)); } for (int i = 0; i < args.length; ++i) { current.setLocal(local++, interpreter.newValue(args[i])); if (args[i].getSize() == 2) { current.setLocal(local++, interpreter.newValue(null)); } } while (local < m.maxLocals) { current.setLocal(local++, interpreter.newValue(null)); } merge(0, current, null); // control flow analysis while (top > 0) { int insn = queue[--top]; Frame f = frames[insn]; Subroutine subroutine = subroutines[insn]; queued[insn] = false; try { AbstractInsnNode insnNode = m.instructions.get(insn); int insnOpcode = insnNode.getOpcode(); int insnType = insnNode.getType(); if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) { merge(insn + 1, f, subroutine); newControlFlowEdge(insn, insn + 1); } else { current.init(f).execute(insnNode, interpreter); subroutine = subroutine == null ? null : subroutine.copy(); if (insnNode instanceof JumpInsnNode) { JumpInsnNode j = (JumpInsnNode) insnNode; if (insnOpcode != GOTO && insnOpcode != JSR) { merge(insn + 1, current, subroutine); newControlFlowEdge(insn, insn + 1); } int jump = insns.indexOf(j.label); if (insnOpcode == JSR) { merge(jump, current, new Subroutine(j.label, m.maxLocals, j)); } else { merge(jump, current, subroutine); } newControlFlowEdge(insn, jump); } else if (insnNode instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; int jump = insns.indexOf(lsi.dflt); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); for (int j = 0; j < lsi.labels.size(); ++j) { LabelNode label = (LabelNode) lsi.labels.get(j); jump = insns.indexOf(label); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); } } else if (insnNode instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; int jump = insns.indexOf(tsi.dflt); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); for (int j = 0; j < tsi.labels.size(); ++j) { LabelNode label = (LabelNode) tsi.labels.get(j); jump = insns.indexOf(label); merge(jump, current, subroutine); newControlFlowEdge(insn, jump); } } else if (insnOpcode == RET) { if (subroutine == null) { throw new AnalyzerException("RET instruction outside of a sub routine"); } for (int i = 0; i < subroutine.callers.size(); ++i) { Object caller = subroutine.callers.get(i); int call = insns.indexOf((AbstractInsnNode) caller); if (frames[call] != null) { merge(call + 1, frames[call], current, subroutines[call], subroutine.access); newControlFlowEdge(insn, call + 1); } } } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) { if (subroutine != null) { if (insnNode instanceof VarInsnNode) { int var = ((VarInsnNode) insnNode).var; subroutine.access[var] = true; if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE || insnOpcode == DSTORE) { subroutine.access[var + 1] = true; } } else if (insnNode instanceof IincInsnNode) { int var = ((IincInsnNode) insnNode).var; subroutine.access[var] = true; } } merge(insn + 1, current, subroutine); newControlFlowEdge(insn, insn + 1); } } List insnHandlers = handlers[insn]; if (insnHandlers != null) { for (int i = 0; i < insnHandlers.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); Type type; if (tcb.type == null) { type = Type.getObjectType("java/lang/Throwable"); } else { type = Type.getObjectType(tcb.type); } int jump = insns.indexOf(tcb.handler); if (newControlFlowExceptionEdge(insn, jump)) { handler.init(f); handler.clearStack(); handler.push(interpreter.newValue(type)); merge(jump, handler, subroutine); } } } } catch (AnalyzerException e) { throw new AnalyzerException("Error at instruction " + insn + ": " + e.getMessage(), e); } catch (Exception e) { throw new AnalyzerException("Error at instruction " + insn + ": " + e.getMessage(), e); } } return frames; }
private void findSubroutine(int insn, final Subroutine sub, final List calls) throws AnalyzerException { while (true) { if (insn < 0 || insn >= n) { throw new AnalyzerException("Execution can fall off end of the code"); } if (subroutines[insn] != null) { return; } subroutines[insn] = sub.copy(); AbstractInsnNode node = insns.get(insn); // calls findSubroutine recursively on normal successors if (node instanceof JumpInsnNode) { if (node.getOpcode() == JSR) { // do not follow a JSR, it leads to another subroutine! calls.add(node); } else { JumpInsnNode jnode = (JumpInsnNode) node; findSubroutine(insns.indexOf(jnode.label), sub, calls); } } else if (node instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node; findSubroutine(insns.indexOf(tsnode.dflt), sub, calls); for (int i = tsnode.labels.size() - 1; i >= 0; --i) { LabelNode l = (LabelNode) tsnode.labels.get(i); findSubroutine(insns.indexOf(l), sub, calls); } } else if (node instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node; findSubroutine(insns.indexOf(lsnode.dflt), sub, calls); for (int i = lsnode.labels.size() - 1; i >= 0; --i) { LabelNode l = (LabelNode) lsnode.labels.get(i); findSubroutine(insns.indexOf(l), sub, calls); } } // calls findSubroutine recursively on exception handler successors List insnHandlers = handlers[insn]; if (insnHandlers != null) { for (int i = 0; i < insnHandlers.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); findSubroutine(insns.indexOf(tcb.handler), sub, calls); } } // if insn does not falls through to the next instruction, return. switch (node.getOpcode()) { case GOTO: case RET: case TABLESWITCH: case LOOKUPSWITCH: case IRETURN: case LRETURN: case FRETURN: case DRETURN: case ARETURN: case RETURN: case ATHROW: return; } insn++; } }