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); } } }
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 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); } } } }
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 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; }
// 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; }
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); } }