/** * A utility method that calculates the successors of a given InstructionHandle <B>in the same * subroutine</B>. That means, a RET does not have any successors as defined here. A * JsrInstruction has its physical successor as its successor (opposed to its target) as defined * here. */ private static InstructionHandle[] getSuccessors(InstructionHandle instruction) { final InstructionHandle[] empty = new InstructionHandle[0]; final InstructionHandle[] single = new InstructionHandle[1]; final InstructionHandle[] pair = new InstructionHandle[2]; Instruction inst = instruction.getInstruction(); if (inst instanceof RET) { return empty; } // Terminates method normally. if (inst instanceof ReturnInstruction) { return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW) { return empty; } // See method comment. if (inst instanceof JsrInstruction) { single[0] = instruction.getNext(); return single; } if (inst instanceof GotoInstruction) { single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction) { if (inst instanceof Select) { // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length + 1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else { pair[0] = instruction.getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = instruction.getNext(); return single; }
/** Instrument the specified method to replace mapped calls. */ public void instrument_method(Method m, MethodGen mg) { // Loop through each instruction, making substitutions InstructionList il = mg.getInstructionList(); for (InstructionHandle ih = il.getStart(); ih != null; ) { if (debug_instrument_inst.enabled()) { debug_instrument_inst.log("instrumenting instruction %s%n", ih); // ih.getInstruction().toString(pool.getConstantPool())); } InstructionList new_il = null; // Remember the next instruction to process InstructionHandle next_ih = ih.getNext(); // Get the translation for this instruction (if any) new_il = xform_inst(mg, ih.getInstruction()); if (debug_instrument_inst.enabled()) debug_instrument_inst.log(" new inst: %s%n", new_il); // If this instruction was modified, replace it with the new // instruction list. If this instruction was the target of any // jumps or line numbers , replace them with the first // instruction in the new list replace_instructions(il, ih, new_il); ih = next_ih; } }
byte[] nullAdaptClass(final InputStream is, final String name) throws Exception { JavaClass jc = new ClassParser(is, name + ".class").parse(); ClassGen cg = new ClassGen(jc); String cName = cg.getClassName(); ConstantPoolGen cp = cg.getConstantPool(); Method[] ms = cg.getMethods(); for (int j = 0; j < ms.length; ++j) { MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp); boolean lv = ms[j].getLocalVariableTable() == null; boolean ln = ms[j].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); InstructionList il = mg.getInstructionList(); if (il != null) { InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } } cg.replaceMethod(ms[j], mg.getMethod()); } return cg.getJavaClass().getBytes(); }
/** Build the array of line number information for the optimized instruction sequence. */ private LineNumberInfo[] buildLineNumberInfo() { Vector lineNumbers = new Vector(); for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) { handle.addLineNumberInfo(lineNumbers); } return (LineNumberInfo[]) Utils.toArray(lineNumbers, LineNumberInfo.class); }
/** * Build the array of the instructions resulting from the optimization process. * * @return the array of instructions */ private Instruction[] buildInstructionArray() { int length; // count size of instruction array length = 0; for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) { length += 1; } Instruction[] insns = new Instruction[length]; length = 0; for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) { insns[length] = handle.getInstruction(); length += 1; } return insns; }
private void dumpCode() { int i = 0; for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) { System.err.println( i++ + ":\t" + org.caesarj.classfile.OpcodeNames.getName(handle.getInstruction().getOpcode())); } System.err.flush(); }
private boolean cleanCode() { boolean codeRemoved = false; // Test if all end-instructions are reached... (copied from exception"handlers" see below) for (int j = 0; localVariables != null && j < localVariables.length; j++) { while (!((InstructionHandle) localVariables[j].getEnd()).isReached()) { localVariables[j].setEnd(((InstructionHandle) localVariables[j].getEnd()).getPrevious()); } } for (int i = 0; i < handlers.length; i++) { while (!((InstructionHandle) handlers[i].getEnd()).isReached()) { handlers[i].setEnd(((InstructionHandle) handlers[i].getEnd()).getPrevious()); } // !!!if (start > end) remove handler } InstructionHandle current = codeStart; for (InstructionHandle handle = current.getNext(); handle != null; handle = handle.getNext()) { if (handle.isReached()) { current.setNext(handle); current = handle; } else { current.setNext(null); codeRemoved = true; } /* Andreas start handle.clean(); */ handle._clean(); // Andreas end } if (current == codeStart) { codeStart.setNext(null); } return codeRemoved; }
/** Start the method's visit. */ public void start() { if (!mg.isAbstract() && !mg.isNative()) { for (InstructionHandle ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) { Instruction i = ih.getInstruction(); if (!visitInstruction(i)) i.accept(this); } updateExceptionHandlers(); } }
private boolean optimizeCodeSequence() { boolean codeChanged = false; buildBasicBlocks(codeStart); for (InstructionHandle handle = codeStart; handle != null; handle = handle.getNext()) { codeChanged |= Patterns.optimize(handle); } codeChanged |= cleanCode(); return codeChanged; }
private void buildBasicBlocks(InstructionHandle start) { for (InstructionHandle handle = this.codeStart; handle != null; handle = handle.getNext()) { handle.reset(); } for (int i = 0; i < handlers.length; i++) { // !!! if (start.isReachable()) ((InstructionHandle) handlers[i].getHandler()).addAccessor(handlers[i]); ((InstructionHandle) handlers[i].getStart()).addAccessor(handlers[i]); // !!! WHY ??? graf 010111 // ((InstructionHandle)handlers[i].getEnd()).addAccessor(handlers[i]); // !!! WHY ??? graf 010111 } // add local variable infos as accessors to their start and end instructions in order // to be notified by changes. for (int j = 0; localVariables != null && j < localVariables.length; j++) { ((InstructionHandle) localVariables[j].getEnd()).addAccessor(localVariables[j]); ((InstructionHandle) localVariables[j].getStart()).addAccessor(localVariables[j]); } }
/** * 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>()); }