void setExecuted(ThreadInfo ti, Instruction insn) { int idx = ti.getId(); if (covered == null) { covered = new BitSet[idx + 1]; } else if (idx >= covered.length) { BitSet[] a = new BitSet[idx + 1]; System.arraycopy(covered, 0, a, 0, covered.length); covered = a; } if (covered[idx] == null) { covered[idx] = new BitSet(mi.getInstructions().length); } int off = insn.getInstructionIndex(); covered[idx].set(off); if (showBranchCoverage && (insn instanceof IfInstruction)) { if (branchTrue == null) { branchTrue = new BitSet(mi.getInstructions().length); branchFalse = new BitSet(branchTrue.size()); } if (!((IfInstruction) insn).getConditionValue()) { branchTrue.set(off); } else { branchFalse.set(off); } } }
void printBodyCoverage(MethodCoverage mc) { MethodInfo mi = mc.getMethodInfo(); Instruction[] code = mi.getInstructions(); BitSet cov = mc.getExecutedInsn(); int i, start = -1; BitSet handlers = mc.getHandlers(); if (excludeHandlers) { cov.andNot(handlers); } for (i = 0; i < code.length; i++) { if (!cov.get(i)) { // not covered if (start == -1) { start = i; } } else { // covered if (start != -1) { printSourceRange(code, handlers, start, i - 1, ""); start = -1; } } } if (start != -1) { printSourceRange(code, handlers, start, i - 1, ""); } // now print the missing branches BitSet branches = mc.getBranches(); lastStart = -1; // reset in case condition and branch are in same line for (i = 0; i < code.length; i++) { if (branches.get(i)) { String prefix = ""; BitSet bTrue = mc.branchTrue; BitSet bFalse = mc.branchFalse; if (bTrue != null) { // means we have condition bit sets boolean cTrue = bTrue.get(i); boolean cFalse = bFalse.get(i); if (cTrue) { prefix = cFalse ? "" : "F "; // covered or false missing } else { prefix = cFalse ? "T " : "N "; // true or both missing } } else { prefix = "N "; // not covered at all } if (prefix != null) { printSourceRange(code, handlers, i, i, prefix); } } } }
public void setConstErrorMessage() { MethodInfo mi = insn.getMethodInfo(); StringBuilder sb = new StringBuilder("@Const method violation: "); sb.append(mi.getFullName()); sb.append("\n\tfield: "); sb.append(((FieldInfo) use).getFullName()); sb.append("\n\tmethod: "); sb.append(insn.getSourceLocation()); msg = sb.toString(); }
BitSet getBasicBlocks() { if (basicBlocks == null) { Instruction[] code = mi.getInstructions(); BitSet bb = new BitSet(code.length); bb.set(0); // first insn is always a bb start // first, look at the insn type for (int i = 0; i < code.length; i++) { Instruction insn = code[i]; if (insn instanceof IfInstruction) { IfInstruction ifInsn = (IfInstruction) insn; Instruction tgt = ifInsn.getTarget(); bb.set(tgt.getInstructionIndex()); tgt = ifInsn.getNext(); bb.set(tgt.getInstructionIndex()); } else if (insn instanceof GOTO) { Instruction tgt = ((GOTO) insn).getTarget(); bb.set(tgt.getInstructionIndex()); } else if (insn instanceof InvokeInstruction) { // hmm, this might be a bit too conservative, but who says we // don't jump out of a caller into a handler, or even that we // ever return from the call? Instruction tgt = insn.getNext(); bb.set(tgt.getInstructionIndex()); } } // and now look at the handlers (every first insn is a bb start) ExceptionHandler[] handlers = mi.getExceptions(); if (handlers != null) { for (int i = 0; i < handlers.length; i++) { Instruction tgt = mi.getInstructionAt(handlers[i].getHandler()); bb.set(tgt.getInstructionIndex()); } } basicBlocks = bb; /** dump * System.out.println(); * System.out.println(mi.getFullName()); * for (int i=0; i<code.length; i++) { * System.out.print(String.format("%1$2d %2$c ",i, bb.get(i) ? '>' : ' ')); * System.out.println(code[i]); * } **/ } return basicBlocks; }
BitSet getHandlerStarts() { BitSet b = new BitSet(mi.getInstructions().length); ExceptionHandler[] handler = mi.getExceptions(); if (handler != null) { for (int i = 0; i < handler.length; i++) { Instruction hs = mi.getInstructionAt(handler[i].getHandler()); b.set(hs.getInstructionIndex()); } } return b; }
BitSet getHandlers() { // this algorithm is a bit subtle - we walk through the code until // we hit a forward GOTO (or RETURN). If the insn following the goto is the // beginning of a handler, we mark everything up to the jump address // as a handler block if (handlers == null) { BitSet hs = getHandlerStarts(); Instruction[] code = mi.getInstructions(); BitSet b = new BitSet(code.length); if (!hs.isEmpty()) { for (int i = 0; i < code.length; i++) { Instruction insn = code[i]; if (insn instanceof GOTO) { GOTO gotoInsn = (GOTO) insn; if (!gotoInsn.isBackJump() && hs.get(i + 1)) { // jump around handler int handlerEnd = gotoInsn.getTarget().getInstructionIndex(); for (i++; i < handlerEnd; i++) { b.set(i); } } } else if (insn instanceof ReturnInstruction) { // everything else is handler for (i++; i < code.length; i++) { b.set(i); } } } } handlers = b; } return handlers; }
void setLoaded(ClassInfo ci) { if (methods == null) { this.ci = ci; covered = true; log.info("used class: " + className); methods = new HashMap<MethodInfo, MethodCoverage>(); for (MethodInfo mi : ci.getDeclaredMethodInfos()) { // <2do> what about MJI methods? we should report why we don't cover them if (!mi.isNative() && !mi.isAbstract()) { MethodCoverage mc = new MethodCoverage(mi); methods.put(mi, mc); } } } }
public void instructionExecuted(JVM vm) { ThreadInfo ti = vm.getLastThreadInfo(); Instruction insn = vm.getLastInstruction(); if (insn instanceof VirtualInvocation) { if (vm.getNextInstruction() != insn) { // otherwise we didn't execute VirtualInvocation call = (VirtualInvocation) insn; int ref = call.getCalleeThis(ti); Record rec = getRecord(ref); if (rec != null) { MethodInfo mi = call.getInvokedMethod(ti, ref); if (logCall) { log(ti, "invoke %1$s.%2$s", rec.ei, mi.getUniqueName()); } if (!checkShared(rec, ti, mi, insn)) { return; } } } } else if (insn instanceof PUTFIELD) { PUTFIELD storeInsn = (PUTFIELD) insn; int ref = storeInsn.getLastThis(); Record rec = getRecord(ref); if (rec != null) { FieldInfo fi = storeInsn.getFieldInfo(); if (logPut) { log(ti, "put %1$s.%2$s = <%3$d>", rec.ei, fi.getName(), storeInsn.getLastValue()); } if (!checkShared(rec, ti, fi, insn)) { return; } if (!checkConst(rec, ti, fi, insn)) { return; } } } }
public Instruction execute(SystemState ss, KernelState ks, ThreadInfo ti) { if (!ti.isFirstStepInsn()) { InvocationCG cg = new InvocationCG("INVOKECG", invokes); ss.setNextChoiceGenerator(cg); return this; } else { InvocationCG cg = ss.getCurrentChoiceGenerator("INVOKECG", InvocationCG.class); assert (cg != null) : "no current InvocationCG"; Invocation call = cg.getNextChoice(); MethodInfo callee = call.getMethodInfo(); InstructionFactory insnFactory = MethodInfo.getInstructionFactory(); if (callee.isStatic()) { realInvoke = (InvokeInstruction) insnFactory.create(null, Constants.INVOKESTATIC); } else { realInvoke = (InvokeInstruction) insnFactory.create(null, Constants.INVOKENONVIRTUAL); } realInvoke.init(mi, offset, position); realInvoke.setInvokedMethod( callee.getClassInfo().getName(), callee.getName(), callee.getSignature()); pushArguments(ti, call.getArguments(), call.getAttrs()); return realInvoke; } }
public void executeInstruction(JVM vm) { Instruction insn = vm.getLastInstruction(); MethodInfo mi = insn.getMethodInfo(); ThreadInfo ti = vm.getLastThreadInfo(); if (mi != lastMi) { logStack(ti); lastMi = mi; } else if (insn instanceof InvokeInstruction) { MethodInfo callee; // that's the only little gist of it - if this is a VirtualInvocation, // we have to dig the callee out by ourselves (it's not known // before execution) if (insn instanceof VirtualInvocation) { VirtualInvocation callInsn = (VirtualInvocation) insn; int objref = callInsn.getCalleeThis(ti); callee = callInsn.getInvokedMethod(ti, objref); } else if (insn instanceof INVOKESPECIAL) { INVOKESPECIAL callInsn = (INVOKESPECIAL) insn; callee = callInsn.getInvokedMethod(ti); } else { InvokeInstruction callInsn = (InvokeInstruction) insn; callee = callInsn.getInvokedMethod(ti); } if (callee != null) { if (callee.isMJI()) { logStack(ti); } } else { out.println("ERROR: unknown callee of: " + insn); } } }
MethodCoverage getMethodCoverage(JVM vm) { Instruction insn = vm.getLastInstruction(); if (!insn.isExtendedInstruction()) { MethodInfo mi = insn.getMethodInfo(); if (mi != lastMi) { lastMc = null; lastMi = mi; ClassInfo ci = mi.getClassInfo(); if (ci != null) { ClassCoverage cc = classes.get(ci.getName()); if (cc != null) { lastMc = cc.getMethodCoverage(mi); } } } return lastMc; } return null; }
BitSet getExecutedInsn() { int nTotal = mi.getInstructions().length; BitSet bUnion = new BitSet(nTotal); if (covered != null) { for (BitSet b : covered) { if (b != null) { bUnion.or(b); } } } return bUnion; }
Coverage getCoveredInsn() { int nTotal = mi.getInstructions().length; if (excludeHandlers) { nTotal -= getHandlers().cardinality(); } if (covered != null) { BitSet bExec = getExecutedInsn(); if (excludeHandlers) { bExec.andNot(getHandlers()); } return new Coverage(nTotal, bExec.cardinality()); } else { return new Coverage(nTotal, 0); } }
// that's kind of redundant with basic blocks, but not really - here // we are interested in the logic behind branches, i.e. we want to know // what the condition values were. We are not interested in GOTOs and exceptions BitSet getBranches() { if (branches == null) { Instruction[] code = mi.getInstructions(); BitSet br = new BitSet(code.length); for (int i = 0; i < code.length; i++) { Instruction insn = code[i]; if (insn instanceof IfInstruction) { br.set(i); } } branches = br; } return branches; }
boolean getCoveredLines(BitSet executable, BitSet covered) { Instruction inst[] = mi.getInstructions(); BitSet insn; int i, line; if (covered == null) { return false; } insn = getExecutedInsn(); if (excludeHandlers) { insn.andNot(getHandlers()); } if (branchTrue != null) { for (i = branchTrue.length() - 1; i >= 0; i--) { boolean cTrue = branchTrue.get(i); boolean cFalse = branchFalse.get(i); if ((!cTrue || !cFalse) && (inst[i] instanceof IfInstruction)) { insn.clear(i); } } } for (i = inst.length - 1; i >= 0; i--) { line = inst[i].getLineNumber(); if (line > 0) { executable.set(line); covered.set(line); } } for (i = inst.length - 1; i >= 0; i--) { line = inst[i].getLineNumber(); if ((!insn.get(i)) && (line > 0)) { // TODO What do we do with instructions that don't have a line number. Is // this even possible? covered.clear(line); } } return true; }
protected MethodInfo createCallStub(String originator, int id) { MethodInfo mi = new MethodInfo(id); String cname = ci.getName(); Instruction insn; mi.name = originator + name; // + cname; // could maybe also include the called method, but keep it fast mi.signature = "()V"; mi.maxLocals = isStatic() ? 0 : 1; mi.maxStack = getNumberOfCallerStackSlots(); // <2do> cache for optimization mi.localVariableNames = EMPTY; mi.localVariableTypes = EMPTY; mi.lineNumbers = null; mi.exceptions = null; mi.thrownExceptionClassNames = null; mi.uniqueName = mi.name; // createAndInitialize the code CodeBuilder cb = mi.getCodeBuilder(); if (isStatic()) { mi.modifiers |= Modifier.STATIC; if (isClinit()) { insn = insnFactory.create(null, INVOKECLINIT.OPCODE); } else { insn = insnFactory.create(null, Constants.INVOKESTATIC); } } else if (name.equals("<init>")) { insn = insnFactory.create(null, Constants.INVOKESPECIAL); } else { insn = insnFactory.create(null, Constants.INVOKEVIRTUAL); } ((InvokeInstruction) insn).setInvokedMethod(cname, name, signature); cb.append(insn); insn = insnFactory.create(null, Constants.RETURN); cb.append(insn); cb.setCode(); return mi; }
AnnotationInfo getRequirementsAnnotation(MethodInfo mi) { // <2do> should probably look for overridden method annotations return mi.getAnnotation("gov.nasa.jpf.Requirement"); }
void printMethodCoverages(ClassCoverage cc) { String classNameTree = "cc-" + cc.className.replace('.', '-') + '-'; int line, lineNumbers[]; boolean result = true; if (cc.methods == null) { return; } ArrayList<Map.Entry<MethodInfo, MethodCoverage>> mthEntries = Misc.createSortedEntryList( cc.methods, new Comparator<Map.Entry<MethodInfo, MethodCoverage>>() { public int compare( Map.Entry<MethodInfo, MethodCoverage> o1, Map.Entry<MethodInfo, MethodCoverage> o2) { int a = o2.getValue().getCoveredInsn().percent(); int b = o1.getValue().getCoveredInsn().percent(); if (a == b) { return o2.getKey().getUniqueName().compareTo(o1.getKey().getUniqueName()); } else { return a - b; } } }); for (Map.Entry<MethodInfo, MethodCoverage> e : mthEntries) { MethodCoverage mc = e.getValue(); MethodInfo mi = mc.getMethodInfo(); Coverage insnCoverage = mc.getCoveredInsn(); Coverage lineCoverage = mc.getCoveredLines(); Coverage branchCoverage = mc.getCoveredBranches(); result = result && insnCoverage.isFullyCovered(); HTMLPublisher.writeTableTreeNodeBegin( pw, classNameTree + HTMLPublisher.escape(mi.getLongName())); pw.print(" <td class=\"firstCol\">"); lineNumbers = mi.getLineNumbers(); if ((lineNumbers != null) && (lineNumbers.length > 0)) { line = lineNumbers[0]; } else { line = 0; } ((HTMLPublisher) publisher).writeSourceAnchor(pw, mi.getSourceFileName(), line); pw.print(HTMLPublisher.escape(mi.getLongName())); pw.println("</a></td>"); pw.print(" "); printCoverage(insnCoverage); printCoverage(lineCoverage); printCoverage(mc.getCoveredBasicBlocks()); printCoverage(branchCoverage); pw.println(); HTMLPublisher.writeTableTreeNodeEnd(pw); } }
MethodCoverage(MethodInfo mi) { this.mi = mi; log.info("add method: " + mi.getUniqueName()); }
void printMethodCoverages(ClassCoverage cc) { String space = " "; boolean result = true; if (cc.methods == null) { return; } ArrayList<Map.Entry<MethodInfo, MethodCoverage>> mthEntries = Misc.createSortedEntryList( cc.methods, new Comparator<Map.Entry<MethodInfo, MethodCoverage>>() { public int compare( Map.Entry<MethodInfo, MethodCoverage> o1, Map.Entry<MethodInfo, MethodCoverage> o2) { int a = o2.getValue().getCoveredInsn().percent(); int b = o1.getValue().getCoveredInsn().percent(); if (a == b) { return o2.getKey().getUniqueName().compareTo(o1.getKey().getUniqueName()); } else { return a - b; } } }); Coverage emptyCoverage = new Coverage(0, 0); for (Map.Entry<MethodInfo, MethodCoverage> e : mthEntries) { MethodCoverage mc = e.getValue(); MethodInfo mi = mc.getMethodInfo(); Coverage insnCoverage = mc.getCoveredInsn(); Coverage lineCoverage = mc.getCoveredLines(); Coverage branchCoverage = mc.getCoveredBranches(); result = result && insnCoverage.isFullyCovered(); pw.print(space); printCoverage(insnCoverage); pw.print(space); printCoverage(lineCoverage); pw.print(space); printCoverage(mc.getCoveredBasicBlocks()); pw.print(space); printCoverage(branchCoverage); pw.print(space); printCoverage(emptyCoverage); pw.print(space); pw.print(mi.getLongName()); pw.println(); if (showMethodBodies && (!insnCoverage.isFullyCovered() || !branchCoverage.isFullyCovered())) { printBodyCoverage(mc); } } }
/** @see gov.nasa.jpf.ListenerAdapter#instructionExecuted(gov.nasa.jpf.jvm.JVM) */ public void instructionExecuted(JVM vm) { Instruction instr = vm.getLastInstruction(); ThreadInfo ti = vm.getLastThreadInfo(); if (instr instanceof InvokeInstruction) { InvokeInstruction invInstr = ((InvokeInstruction) instr); String method = invInstr.toString(); // if(method.contains("Test")) // System.out.println(method); MethodInfo mi = ((InvokeInstruction) instr).getInvokedMethod(); if (this.traceDefFilter != null && this.traceDefFilter.accept(mi)) { // Callee ElementInfo calleeElement = ti.getThisElementInfo(); MethodInfo calleeMethod = invInstr.getInvokedMethod(); ClassInfo calleeClass = null; int calleeID = -1; if (calleeMethod.isStatic()) { // static method: method declared in class calleeClass = calleeMethod.getClassInfo(); // static methods do not have a instance calleeID = -1; } else { // non static method: method is maybe overridden. get the current class // instead of the class the method is declared in. calleeClass = calleeElement.getClassInfo(); // get the current instance calleeID = calleeElement.getThisReference(); } assert (calleeClass != null); // Caller ElementInfo callerElement = ti.getElementInfo(ti.getCallerStackFrame().getThis()); if (callerElement != null) { MethodInfo callerMethod = invInstr.getMethodInfo(); ClassInfo callerClass = null; int callerID = -1; if (callerMethod.isStatic()) { // see above callerClass = callerMethod.getClassInfo(); callerID = -1; } else { // see above callerClass = callerElement.getClassInfo(); callerID = callerElement.getThisReference(); } // Arguments Object[] argumentValues = invInstr.getArgumentValues(ti); Object[] arguments = new Object[argumentValues.length]; for (int i = 0; i < arguments.length; i++) { if (this.argumentValues) { if (argumentValues[i] instanceof ElementInfo) arguments[i] = ((ElementInfo) argumentValues[i]).getThisReference(); else arguments[i] = argumentValues[i]; } else arguments[i] = null; } MethodEntry methodEntry = new MethodEntry( callerID, callerMethod, callerClass, calleeID, calleeMethod, calleeClass, arguments, ti.getName()); this.currentStateNode.methods.add(methodEntry); if (this.timeStamps) methodEntry.time = new Date().getTime(); } } } }