| 1 | |
|
| 2 | |
|
| 3 | |
|
| 4 | |
|
| 5 | |
|
| 6 | |
|
| 7 | |
|
| 8 | |
|
| 9 | |
|
| 10 | |
|
| 11 | |
|
| 12 | |
|
| 13 | |
|
| 14 | |
|
| 15 | |
|
| 16 | |
|
| 17 | |
|
| 18 | |
|
| 19 | |
|
| 20 | |
|
| 21 | |
|
| 22 | |
|
| 23 | |
package net.sourceforge.cobertura.instrument; |
| 24 | |
|
| 25 | |
import net.sourceforge.cobertura.util.RegexUtil; |
| 26 | |
|
| 27 | |
import org.objectweb.asm.Label; |
| 28 | |
import org.objectweb.asm.Opcodes; |
| 29 | |
|
| 30 | |
|
| 31 | |
|
| 32 | |
|
| 33 | |
public class SecondPassMethodInstrumenter extends NewLocalVariableMethodAdapter implements Opcodes |
| 34 | |
{ |
| 35 | |
private int currentLine; |
| 36 | |
|
| 37 | |
private int currentJump; |
| 38 | |
|
| 39 | |
private boolean methodStarted; |
| 40 | |
|
| 41 | |
private int myVariableIndex; |
| 42 | |
|
| 43 | |
private Label startLabel; |
| 44 | |
|
| 45 | |
private Label endLabel; |
| 46 | |
|
| 47 | |
private JumpHolder lastJump; |
| 48 | |
|
| 49 | |
private FirstPassMethodInstrumenter firstPass; |
| 50 | |
|
| 51 | |
private static final int BOOLEAN_TRUE = ICONST_0; |
| 52 | |
private static final int BOOLEAN_FALSE = ICONST_1; |
| 53 | |
|
| 54 | |
public SecondPassMethodInstrumenter(FirstPassMethodInstrumenter firstPass) |
| 55 | |
{ |
| 56 | 35 | super(firstPass.getWriterMethodVisitor(), firstPass.getMyAccess(), firstPass.getMyDescriptor(), 2); |
| 57 | 35 | this.firstPass = firstPass; |
| 58 | 35 | this.currentLine = 0; |
| 59 | 35 | } |
| 60 | |
|
| 61 | |
public void visitJumpInsn(int opcode, Label label) |
| 62 | |
{ |
| 63 | |
|
| 64 | 11 | touchBranchFalse(); |
| 65 | |
|
| 66 | |
|
| 67 | |
|
| 68 | |
|
| 69 | |
|
| 70 | |
|
| 71 | 11 | if ((opcode != GOTO) && (opcode != JSR) && (currentLine != 0) |
| 72 | |
&& (!this.firstPass.getMyName().equals("<clinit>"))) |
| 73 | |
{ |
| 74 | 7 | lastJump = new JumpHolder(currentLine, currentJump++); |
| 75 | 7 | mv.visitIntInsn(SIPUSH, currentLine); |
| 76 | 7 | mv.visitVarInsn(ISTORE, myVariableIndex); |
| 77 | 7 | mv.visitIntInsn(SIPUSH, lastJump.getJumpNumber()); |
| 78 | 7 | mv.visitVarInsn(ISTORE, myVariableIndex + 1); |
| 79 | |
} |
| 80 | |
|
| 81 | 11 | super.visitJumpInsn(opcode, label); |
| 82 | 11 | } |
| 83 | |
|
| 84 | |
public void visitLineNumber(int line, Label start) |
| 85 | |
{ |
| 86 | |
|
| 87 | 108 | currentLine = line; |
| 88 | 108 | currentJump = 0; |
| 89 | |
|
| 90 | 108 | instrumentGetClassData(); |
| 91 | |
|
| 92 | |
|
| 93 | |
|
| 94 | 108 | mv.visitIntInsn(SIPUSH, line); |
| 95 | 108 | mv.visitMethodInsn(INVOKEVIRTUAL, |
| 96 | |
"net/sourceforge/cobertura/coveragedata/ClassData", "touch", |
| 97 | |
"(I)V"); |
| 98 | |
|
| 99 | 108 | super.visitLineNumber(line, start); |
| 100 | 108 | } |
| 101 | |
|
| 102 | |
public void visitMethodInsn(int opcode, String owner, String name, |
| 103 | |
String desc) |
| 104 | |
{ |
| 105 | |
|
| 106 | 38 | touchBranchFalse(); |
| 107 | |
|
| 108 | 38 | super.visitMethodInsn(opcode, owner, name, desc); |
| 109 | |
|
| 110 | |
|
| 111 | |
|
| 112 | 38 | if (RegexUtil.matches(firstPass.getIgnoreRegexs(), owner)) |
| 113 | |
{ |
| 114 | 2 | firstPass.removeLine(currentLine); |
| 115 | |
} |
| 116 | 38 | } |
| 117 | |
|
| 118 | |
public void visitFieldInsn(int opcode, String owner, String name, String desc) |
| 119 | |
{ |
| 120 | |
|
| 121 | 12 | touchBranchFalse(); |
| 122 | |
|
| 123 | 12 | super.visitFieldInsn(opcode, owner, name, desc); |
| 124 | 12 | } |
| 125 | |
|
| 126 | |
public void visitIincInsn(int var, int increment) |
| 127 | |
{ |
| 128 | |
|
| 129 | 1 | touchBranchFalse(); |
| 130 | |
|
| 131 | 1 | super.visitIincInsn(var, increment); |
| 132 | 1 | } |
| 133 | |
|
| 134 | |
public void visitInsn(int opcode) |
| 135 | |
{ |
| 136 | |
|
| 137 | 70 | touchBranchFalse(); |
| 138 | |
|
| 139 | 70 | super.visitInsn(opcode); |
| 140 | 70 | } |
| 141 | |
|
| 142 | |
public void visitIntInsn(int opcode, int operand) |
| 143 | |
{ |
| 144 | |
|
| 145 | 0 | touchBranchFalse(); |
| 146 | |
|
| 147 | 0 | super.visitIntInsn(opcode, operand); |
| 148 | 0 | } |
| 149 | |
|
| 150 | |
public void visitLabel(Label label) |
| 151 | |
{ |
| 152 | |
|
| 153 | 146 | if (methodStarted) |
| 154 | |
{ |
| 155 | 35 | methodStarted = false; |
| 156 | 35 | myVariableIndex = getFirstStackVariable(); |
| 157 | 35 | mv.visitInsn(ICONST_0); |
| 158 | 35 | mv.visitVarInsn(ISTORE, myVariableIndex); |
| 159 | 35 | mv.visitIntInsn(SIPUSH, -1); |
| 160 | 35 | mv.visitVarInsn(ISTORE, myVariableIndex + 1); |
| 161 | 35 | startLabel = label; |
| 162 | |
} |
| 163 | |
|
| 164 | 146 | endLabel = label; |
| 165 | |
|
| 166 | 146 | super.visitLabel(label); |
| 167 | |
|
| 168 | |
|
| 169 | 146 | if (firstPass.getJumpTargetLabels().keySet().contains(label)) |
| 170 | |
{ |
| 171 | 7 | if (lastJump != null) |
| 172 | |
{ |
| 173 | 4 | Label newLabelX = instrumentIsLastJump(); |
| 174 | 4 | instrumentGetClassData(); |
| 175 | 4 | instrumentPutLineAndBranchNumbers(); |
| 176 | 4 | mv.visitInsn(BOOLEAN_FALSE); |
| 177 | 4 | instrumentInvokeTouchJump(); |
| 178 | 4 | Label newLabelY = new Label(); |
| 179 | 4 | mv.visitJumpInsn(GOTO, newLabelY); |
| 180 | 4 | mv.visitLabel(newLabelX); |
| 181 | 4 | mv.visitVarInsn(ILOAD, myVariableIndex + 1); |
| 182 | 4 | mv.visitJumpInsn(IFLT, newLabelY); |
| 183 | 4 | instrumentGetClassData(); |
| 184 | 4 | instrumentPutLineAndBranchNumbers(); |
| 185 | 4 | mv.visitInsn(BOOLEAN_TRUE); |
| 186 | 4 | instrumentInvokeTouchJump(); |
| 187 | 4 | mv.visitLabel(newLabelY); |
| 188 | 4 | } |
| 189 | |
else |
| 190 | |
{ |
| 191 | |
|
| 192 | 3 | mv.visitVarInsn(ILOAD, myVariableIndex + 1); |
| 193 | 3 | Label newLabelX = new Label(); |
| 194 | 3 | mv.visitJumpInsn(IFLT, newLabelX); |
| 195 | 3 | instrumentJumpHit(true); |
| 196 | 3 | mv.visitLabel(newLabelX); |
| 197 | |
} |
| 198 | 3 | } |
| 199 | 139 | else if (lastJump != null) |
| 200 | |
{ |
| 201 | 1 | Label newLabelX = instrumentIsLastJump(); |
| 202 | 1 | instrumentJumpHit(false); |
| 203 | 1 | mv.visitLabel(newLabelX); |
| 204 | |
} |
| 205 | 146 | lastJump = null; |
| 206 | |
|
| 207 | 146 | SwitchHolder sh = (SwitchHolder) firstPass.getSwitchTargetLabels().get(label); |
| 208 | 146 | if (sh != null) |
| 209 | |
{ |
| 210 | 13 | instrumentSwitchHit(sh.getLineNumber(), sh.getSwitchNumber(), sh.getBranch()); |
| 211 | |
} |
| 212 | |
|
| 213 | |
|
| 214 | 146 | Integer line = (Integer) firstPass.getLineLabels().get(label); |
| 215 | 146 | if (line != null) { |
| 216 | 108 | visitLineNumber(line.intValue(), label); |
| 217 | |
} |
| 218 | 146 | } |
| 219 | |
|
| 220 | |
public void visitLdcInsn(Object cst) |
| 221 | |
{ |
| 222 | |
|
| 223 | 21 | touchBranchFalse(); |
| 224 | |
|
| 225 | 21 | super.visitLdcInsn(cst); |
| 226 | 21 | } |
| 227 | |
|
| 228 | |
public void visitMultiANewArrayInsn(String desc, int dims) |
| 229 | |
{ |
| 230 | |
|
| 231 | 1 | touchBranchFalse(); |
| 232 | |
|
| 233 | 1 | super.visitMultiANewArrayInsn(desc, dims); |
| 234 | 1 | } |
| 235 | |
|
| 236 | |
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) |
| 237 | |
{ |
| 238 | |
|
| 239 | 1 | touchBranchFalse(); |
| 240 | |
|
| 241 | 1 | super.visitLookupSwitchInsn(dflt, keys, labels); |
| 242 | 1 | } |
| 243 | |
|
| 244 | |
public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) |
| 245 | |
{ |
| 246 | |
|
| 247 | 1 | touchBranchFalse(); |
| 248 | |
|
| 249 | 1 | super.visitTableSwitchInsn(min, max, dflt, labels); |
| 250 | 1 | } |
| 251 | |
|
| 252 | |
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) |
| 253 | |
{ |
| 254 | |
|
| 255 | 3 | touchBranchFalse(); |
| 256 | |
|
| 257 | 3 | super.visitTryCatchBlock(start, end, handler, type); |
| 258 | 3 | } |
| 259 | |
|
| 260 | |
public void visitTypeInsn(int opcode, String desc) |
| 261 | |
{ |
| 262 | |
|
| 263 | 2 | touchBranchFalse(); |
| 264 | |
|
| 265 | 2 | super.visitTypeInsn(opcode, desc); |
| 266 | 2 | } |
| 267 | |
|
| 268 | |
public void visitVarInsn(int opcode, int var) |
| 269 | |
{ |
| 270 | |
|
| 271 | 66 | touchBranchFalse(); |
| 272 | |
|
| 273 | |
|
| 274 | 66 | super.visitVarInsn(opcode, var); |
| 275 | 66 | } |
| 276 | |
|
| 277 | |
public void visitCode() |
| 278 | |
{ |
| 279 | 35 | methodStarted = true; |
| 280 | 35 | super.visitCode(); |
| 281 | 35 | } |
| 282 | |
|
| 283 | |
private void touchBranchFalse() { |
| 284 | 227 | if (lastJump != null) { |
| 285 | 2 | lastJump = null; |
| 286 | 2 | instrumentJumpHit(false); |
| 287 | |
} |
| 288 | 227 | } |
| 289 | |
|
| 290 | |
private void instrumentGetClassData() |
| 291 | |
{ |
| 292 | |
|
| 293 | |
|
| 294 | 135 | mv.visitMethodInsn(INVOKESTATIC, |
| 295 | |
"net/sourceforge/cobertura/coveragedata/ProjectData", |
| 296 | |
"getGlobalProjectData", |
| 297 | |
"()Lnet/sourceforge/cobertura/coveragedata/ProjectData;"); |
| 298 | |
|
| 299 | |
|
| 300 | |
|
| 301 | 135 | mv.visitLdcInsn(firstPass.getOwnerClass()); |
| 302 | 135 | mv |
| 303 | |
.visitMethodInsn(INVOKEVIRTUAL, |
| 304 | |
"net/sourceforge/cobertura/coveragedata/ProjectData", |
| 305 | |
"getOrCreateClassData", |
| 306 | |
"(Ljava/lang/String;)Lnet/sourceforge/cobertura/coveragedata/ClassData;"); |
| 307 | 135 | } |
| 308 | |
|
| 309 | |
private void instrumentSwitchHit(int lineNumber, int switchNumber, int branch) |
| 310 | |
{ |
| 311 | 13 | instrumentGetClassData(); |
| 312 | |
|
| 313 | |
|
| 314 | 13 | mv.visitIntInsn(SIPUSH, lineNumber); |
| 315 | 13 | mv.visitIntInsn(SIPUSH, switchNumber); |
| 316 | 13 | mv.visitIntInsn(SIPUSH, branch); |
| 317 | 13 | instrumentInvokeTouchSwitch(); |
| 318 | 13 | } |
| 319 | |
|
| 320 | |
private void instrumentJumpHit(boolean branch) |
| 321 | |
{ |
| 322 | 6 | instrumentGetClassData(); |
| 323 | |
|
| 324 | |
|
| 325 | 6 | instrumentPutLineAndBranchNumbers(); |
| 326 | 6 | mv.visitInsn(branch ? BOOLEAN_TRUE : BOOLEAN_FALSE); |
| 327 | 6 | instrumentInvokeTouchJump(); |
| 328 | 6 | } |
| 329 | |
|
| 330 | |
private void instrumentInvokeTouchJump() |
| 331 | |
{ |
| 332 | 14 | mv.visitMethodInsn(INVOKEVIRTUAL, "net/sourceforge/cobertura/coveragedata/ClassData", "touchJump", "(IIZ)V"); |
| 333 | 14 | mv.visitIntInsn(SIPUSH, -1); |
| 334 | 14 | mv.visitVarInsn(ISTORE, myVariableIndex + 1); |
| 335 | 14 | } |
| 336 | |
|
| 337 | |
private void instrumentInvokeTouchSwitch() |
| 338 | |
{ |
| 339 | 13 | mv.visitMethodInsn(INVOKEVIRTUAL, "net/sourceforge/cobertura/coveragedata/ClassData", "touchSwitch", "(III)V"); |
| 340 | 13 | } |
| 341 | |
|
| 342 | |
private void instrumentPutLineAndBranchNumbers() |
| 343 | |
{ |
| 344 | 14 | mv.visitVarInsn(ILOAD, myVariableIndex); |
| 345 | 14 | mv.visitVarInsn(ILOAD, myVariableIndex + 1); |
| 346 | 14 | } |
| 347 | |
|
| 348 | |
private Label instrumentIsLastJump() { |
| 349 | 5 | mv.visitVarInsn(ILOAD, myVariableIndex); |
| 350 | 5 | mv.visitIntInsn(SIPUSH, lastJump.getLineNumber()); |
| 351 | 5 | Label newLabelX = new Label(); |
| 352 | 5 | mv.visitJumpInsn(IF_ICMPNE, newLabelX); |
| 353 | 5 | mv.visitVarInsn(ILOAD, myVariableIndex + 1); |
| 354 | 5 | mv.visitIntInsn(SIPUSH, lastJump.getJumpNumber()); |
| 355 | 5 | mv.visitJumpInsn(IF_ICMPNE, newLabelX); |
| 356 | 5 | return newLabelX; |
| 357 | |
} |
| 358 | |
|
| 359 | |
public void visitMaxs(int maxStack, int maxLocals) |
| 360 | |
{ |
| 361 | 35 | mv.visitLocalVariable("__cobertura__line__number__", "I", null, startLabel, endLabel, myVariableIndex); |
| 362 | 35 | mv.visitLocalVariable("__cobertura__branch__number__", "I", null, startLabel, endLabel, myVariableIndex + 1); |
| 363 | 35 | super.visitMaxs(maxStack, maxLocals); |
| 364 | 35 | } |
| 365 | |
|
| 366 | |
} |