private static void addTimer(ClassGen cgen, Method method) { // set up the construction tools InstructionFactory ifact = new InstructionFactory(cgen); InstructionList ilist = new InstructionList(); ConstantPoolGen pgen = cgen.getConstantPool(); String cname = cgen.getClassName(); MethodGen wrapgen = new MethodGen(method, cname, pgen); wrapgen.setInstructionList(ilist); // rename a copy of the original method MethodGen methgen = new MethodGen(method, cname, pgen); cgen.removeMethod(method); String iname = methgen.getName() + "_timing"; methgen.setName(iname); cgen.addMethod(methgen.getMethod()); Type result = methgen.getReturnType(); // compute the size of the calling parameters Type[] parameters = methgen.getArgumentTypes(); int stackIndex = methgen.isStatic() ? 0 : 1; for (int i = 0; i < parameters.length; i++) { stackIndex += parameters[i].getSize(); } // save time prior to invocation ilist.append( ifact.createInvoke( "java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC)); ilist.append(InstructionFactory.createStore(Type.LONG, stackIndex)); // call the wrapped method int offset = 0; short invoke = Constants.INVOKESTATIC; if (!methgen.isStatic()) { ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0)); offset = 1; invoke = Constants.INVOKEVIRTUAL; } for (int i = 0; i < parameters.length; i++) { Type type = parameters[i]; ilist.append(InstructionFactory.createLoad(type, offset)); offset += type.getSize(); } ilist.append(ifact.createInvoke(cname, iname, result, parameters, invoke)); // store result for return later if (result != Type.VOID) { ilist.append(InstructionFactory.createStore(result, stackIndex + 2)); } // print time required for method call ilist.append( ifact.createFieldAccess( "java.lang.System", "out", new ObjectType("java.io.PrintStream"), Constants.GETSTATIC)); ilist.append(InstructionConstants.DUP); ilist.append(InstructionConstants.DUP); String text = "Call to method " + methgen.getName() + " took "; ilist.append(new PUSH(pgen, text)); ilist.append( ifact.createInvoke( "java.io.PrintStream", "print", Type.VOID, new Type[] {Type.STRING}, Constants.INVOKEVIRTUAL)); ilist.append( ifact.createInvoke( "java.lang.System", "currentTimeMillis", Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC)); ilist.append(InstructionFactory.createLoad(Type.LONG, stackIndex)); ilist.append(InstructionConstants.LSUB); ilist.append( ifact.createInvoke( "java.io.PrintStream", "print", Type.VOID, new Type[] {Type.LONG}, Constants.INVOKEVIRTUAL)); ilist.append(new PUSH(pgen, " ms.")); ilist.append( ifact.createInvoke( "java.io.PrintStream", "println", Type.VOID, new Type[] {Type.STRING}, Constants.INVOKEVIRTUAL)); // return result from wrapped method call if (result != Type.VOID) { ilist.append(InstructionFactory.createLoad(result, stackIndex + 2)); } ilist.append(InstructionFactory.createReturn(result)); // finalize the constructed method wrapgen.stripAttributes(true); wrapgen.setMaxStack(); wrapgen.setMaxLocals(); cgen.addMethod(wrapgen.getMethod()); ilist.dispose(); }
/** * Whenever the outgoing frame situation of an InstructionContext changes, all its successors are * put [back] into the queue [as if they were unvisited]. The proof of termination is about the * existence of a fix point of frame merging. */ private void circulationPump( MethodGen m, ControlFlowGraph cfg, InstructionContext start, Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev) { final Random random = new Random(); InstructionContextQueue icq = new InstructionContextQueue(); start.execute( vanillaFrame, new ArrayList<InstructionContext>(), icv, ev); // new ArrayList() <=> no Instruction was executed before // => Top-Level routine (no jsr call before) icq.add(start, new ArrayList<InstructionContext>()); // LOOP! while (!icq.isEmpty()) { InstructionContext u; ArrayList<InstructionContext> ec; if (!DEBUG) { int r = random.nextInt(icq.size()); u = icq.getIC(r); ec = icq.getEC(r); icq.remove(r); } else { u = icq.getIC(0); ec = icq.getEC(0); icq.remove(0); } @SuppressWarnings("unchecked") // ec is of type ArrayList<InstructionContext> ArrayList<InstructionContext> oldchain = (ArrayList<InstructionContext>) (ec.clone()); @SuppressWarnings("unchecked") // ec is of type ArrayList<InstructionContext> ArrayList<InstructionContext> newchain = (ArrayList<InstructionContext>) (ec.clone()); newchain.add(u); if ((u.getInstruction().getInstruction()) instanceof RET) { // System.err.println(u); // We can only follow _one_ successor, the one after the // JSR that was recently executed. RET ret = (RET) (u.getInstruction().getInstruction()); ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain).getLocals().get(ret.getIndex()); InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); // Sanity check InstructionContext lastJSR = null; int skip_jsr = 0; for (int ss = oldchain.size() - 1; ss >= 0; ss--) { if (skip_jsr < 0) { throw new AssertionViolatedException("More RET than JSR in execution chain?!"); } // System.err.println("+"+oldchain.get(ss)); if ((oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction) { if (skip_jsr == 0) { lastJSR = oldchain.get(ss); break; } skip_jsr--; } if ((oldchain.get(ss)).getInstruction().getInstruction() instanceof RET) { skip_jsr++; } } if (lastJSR == null) { throw new AssertionViolatedException( "RET without a JSR before in ExecutionChain?! EC: '" + oldchain + "'."); } JsrInstruction jsr = (JsrInstruction) (lastJSR.getInstruction().getInstruction()); if (theSuccessor != (cfg.contextOf(jsr.physicalSuccessor()))) { throw new AssertionViolatedException( "RET '" + u.getInstruction() + "' info inconsistent: jump back to '" + theSuccessor + "' or '" + cfg.contextOf(jsr.physicalSuccessor()) + "'?"); } if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { @SuppressWarnings( "unchecked") // newchain is already of type ArrayList<InstructionContext> ArrayList<InstructionContext> newchainClone = (ArrayList<InstructionContext>) newchain.clone(); icq.add(theSuccessor, newchainClone); } } else { // "not a ret" // Normal successors. Add them to the queue of successors. InstructionContext[] succs = u.getSuccessors(); for (InstructionContext v : succs) { if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { @SuppressWarnings( "unchecked") // newchain is already of type ArrayList<InstructionContext> ArrayList<InstructionContext> newchainClone = (ArrayList<InstructionContext>) newchain.clone(); icq.add(v, newchainClone); } } } // end "not a ret" // Exception Handlers. Add them to the queue of successors. // [subroutines are never protected; mandated by JustIce] ExceptionHandler[] exc_hds = u.getExceptionHandlers(); for (ExceptionHandler exc_hd : exc_hds) { InstructionContext v = cfg.contextOf(exc_hd.getHandlerStart()); // TODO: the "oldchain" and "newchain" is used to determine the subroutine // we're in (by searching for the last JSR) by the InstructionContext // implementation. Therefore, we should not use this chain mechanism // when dealing with exception handlers. // Example: a JSR with an exception handler as its successor does not // mean we're in a subroutine if we go to the exception handler. // We should address this problem later; by now we simply "cut" the chain // by using an empty chain for the exception handlers. // if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack // (u.getOutFrame().getStack().maxStack(), (exc_hds[s].getExceptionType()==null? // Type.THROWABLE : exc_hds[s].getExceptionType())) ), newchain), icv, ev){ // icq.add(v, (ArrayList) newchain.clone()); if (v.execute( new Frame( u.getOutFrame(oldchain).getLocals(), new OperandStack( u.getOutFrame(oldchain).getStack().maxStack(), (exc_hd.getExceptionType() == null ? Type.THROWABLE : exc_hd.getExceptionType()))), new ArrayList<InstructionContext>(), icv, ev)) { icq.add(v, new ArrayList<InstructionContext>()); } } } // while (!icq.isEmpty()) END InstructionHandle ih = start.getInstruction(); do { if ((ih.getInstruction() instanceof ReturnInstruction) && (!(cfg.isDead(ih)))) { InstructionContext ic = cfg.contextOf(ih); Frame f = ic.getOutFrame( new ArrayList< InstructionContext>()); // TODO: This is buggy, we check only the top-level // return instructions this way. Maybe some maniac // returns from a method when in a subroutine? LocalVariables lvs = f.getLocals(); for (int i = 0; i < lvs.maxLocals(); i++) { if (lvs.get(i) instanceof UninitializedObjectType) { this.addMessage( "Warning: ReturnInstruction '" + ic + "' may leave method with an uninitialized object in the local variables array '" + lvs + "'."); } } OperandStack os = f.getStack(); for (int i = 0; i < os.size(); i++) { if (os.peek(i) instanceof UninitializedObjectType) { this.addMessage( "Warning: ReturnInstruction '" + ic + "' may leave method with an uninitialized object on the operand stack '" + os + "'."); } } // see JVM $4.8.2 // TODO implement all based on stack Type returnedType = null; InstructionHandle ihPrev = null; ihPrev = ih.getPrev(); if (ihPrev != null) { if (ihPrev.getInstruction() instanceof InvokeInstruction) { returnedType = ((InvokeInstruction) ihPrev.getInstruction()).getType(m.getConstantPool()); } if (ihPrev.getInstruction() instanceof LoadInstruction) { int index = ((LoadInstruction) ihPrev.getInstruction()).getIndex(); returnedType = lvs.get(index); } if (ihPrev.getInstruction() instanceof GETFIELD) { returnedType = ((GETFIELD) ihPrev.getInstruction()).getType(m.getConstantPool()); } } if (returnedType != null) { if (returnedType instanceof ObjectType) { try { if (!((ObjectType) returnedType).isAssignmentCompatibleWith(m.getReturnType())) { throw new StructuralCodeConstraintException( "Returned type " + returnedType + " does not match Method's return type " + m.getReturnType()); } } catch (ClassNotFoundException e) { // dont know what do do now, so raise RuntimeException throw new RuntimeException(e); } } else if (!returnedType.equals(m.getReturnType())) { throw new StructuralCodeConstraintException( "Returned type " + returnedType + " does not match Method's return type " + m.getReturnType()); } } } } while ((ih = ih.getNext()) != null); }