1 package net.firstpartners.nounit.reader.bytecode; 2 3 10 11 import java.io.IOException ; 12 import java.util.HashMap ; 13 import java.util.HashSet ; 14 import java.util.Iterator ; 15 16 import net.firstpartners.nounit.reader.ISnippetFactory; 17 import net.firstpartners.nounit.snippet.SnippetCalls; 18 import net.firstpartners.nounit.snippet.Snippets; 19 import net.firstpartners.nounit.utility.NoUnitException; 20 21 import org.apache.log4j.Logger; 22 23 import org.gjt.jclasslib.bytecode.AbstractInstruction; 24 import org.gjt.jclasslib.bytecode.BranchInstruction; 25 import org.gjt.jclasslib.bytecode.ImmediateByteInstruction; 26 import org.gjt.jclasslib.bytecode.ImmediateIntInstruction; 27 import org.gjt.jclasslib.bytecode.ImmediateShortInstruction; 28 import org.gjt.jclasslib.bytecode.IncrementInstruction; 29 import org.gjt.jclasslib.bytecode.InvokeInterfaceInstruction; 30 import org.gjt.jclasslib.bytecode.LookupSwitchInstruction; 31 import org.gjt.jclasslib.bytecode.MultianewarrayInstruction; 32 import org.gjt.jclasslib.bytecode.Opcodes; 33 import org.gjt.jclasslib.bytecode.OpcodesUtil; 34 import org.gjt.jclasslib.bytecode.TableSwitchInstruction; 35 import org.gjt.jclasslib.bytecode.MatchOffsetPair; 36 import org.gjt.jclasslib.io.ByteCodeReader; 37 import org.gjt.jclasslib.structures.AttributeInfo; 38 import org.gjt.jclasslib.structures.ClassFile; 39 import org.gjt.jclasslib.structures.InvalidByteCodeException; 40 import org.gjt.jclasslib.structures.MethodInfo; 41 import org.gjt.jclasslib.structures.attributes.CodeAttribute; 42 43 44 45 50 public class ByteCodeCallsSnippetFactory 51 extends AbstractByteCodeSnippetFactory 52 implements ISnippetFactory, Opcodes { 53 54 57 private CodeAttribute attribute; 58 59 62 private ClassFile classFile; 63 64 private HashMap offsetToPosition = new HashMap (); 65 private int opcodeCounterWidth; 66 private int offsetWidth; 67 68 static Logger log = Logger.getLogger(ByteCodeCallsSnippetFactory.class); 70 71 72 75 private HashMap internalInstructions = new HashMap (); 76 77 80 private int currentInstructionPosition=0; 81 82 83 86 private HashSet methodCalls= new HashSet (); 87 88 89 92 private static final int I_NORMAL =0; 93 94 97 private static final int I_CALL =1; 98 99 100 101 109 public ByteCodeCallsSnippetFactory(MethodInfo thisMethod, ClassFile classFile) 110 throws IOException , InvalidByteCodeException, NoUnitException { 111 112 CodeAttribute attribute; 114 int counter=0; 115 boolean foundFlag=false; 116 117 AttributeInfo[] genAttributes =thisMethod.getAttributes(); 120 121 122 while((counter < genAttributes.length)&&(!foundFlag)){ 123 124 if (genAttributes[counter] instanceof CodeAttribute){ 126 127 foundFlag=true; 129 130 132 133 log.debug(genAttributes[counter].getClass().toString()); 134 135 attribute = (CodeAttribute)genAttributes[counter]; 136 137 this.attribute = attribute; 139 this.classFile = classFile; 140 141 setupDocument(); 142 143 } else { 144 counter++; 145 } 146 } 147 148 } 149 150 157 public ByteCodeCallsSnippetFactory(CodeAttribute attribute, ClassFile classFile) throws IOException , InvalidByteCodeException { 158 159 this.attribute = attribute; 160 this.classFile = classFile; 161 162 setupDocument(); 163 } 164 165 169 public String toString() { 170 171 StringBuffer internalByteCodes = new StringBuffer (); 172 173 for (int a=0; a<this.currentInstructionPosition; a++) { 175 176 internalByteCodes.append(this.internalInstructions.get(String.valueOf(a))); 177 178 } 179 180 return internalByteCodes.toString(); 181 } 182 183 192 public Snippets getSnippets() throws NoUnitException { 193 194 195 int thisInstruction; 197 String tmpString; 198 String tmpClass; 199 String tmpMethod; 200 Snippets calls = new Snippets(); 201 SnippetCalls tmpSnippet ; 202 Iterator myLoop = methodCalls.iterator(); 203 204 205 while (myLoop.hasNext()) { 207 208 210 thisInstruction = ((Integer )myLoop.next()).intValue(); 212 thisInstruction++; tmpString = (String )this.internalInstructions.get(String.valueOf(thisInstruction)); 214 215 tmpClass = getClassFromCalledString(tmpString); 217 tmpMethod = getMethodFromCalledString(tmpString); 218 tmpSnippet= new SnippetCalls(tmpClass,tmpMethod,null); 219 calls.add(tmpSnippet); 220 221 } 222 223 return calls; 224 } 225 226 227 228 232 protected void appendString(String string) { 233 234 appendString(I_NORMAL,string); 235 236 } 237 238 243 protected void appendString(int type,String string) { 244 245 246 if (string!=null) { 248 249 if ((type==I_CALL)&&(this.doubleCheckCalledMethod(currentInstructionPosition))) { 251 this.methodCalls.add(new Integer (currentInstructionPosition)); 252 253 } 254 255 internalInstructions.put( 257 String.valueOf(this.currentInstructionPosition),string); 258 currentInstructionPosition++; 259 260 261 } 262 } 263 264 265 268 private void setupDocument() 269 throws IOException , InvalidByteCodeException { 270 271 byte[] code = attribute.getCode(); 272 273 java.util.List instructions = ByteCodeReader.readByteCode(code); 274 275 277 int[] linesPerOpcode = new int[instructions.size()]; 278 279 Iterator it = instructions.iterator(); 280 AbstractInstruction currentInstruction; 281 int instructionCount = 0; 282 while (it.hasNext()) { 283 currentInstruction = (AbstractInstruction)it.next(); 284 linesPerOpcode[instructionCount++] = addInstructionToDocument(currentInstruction); 285 } 286 287 createOpcodeCounterDocument(linesPerOpcode); 288 289 290 } 291 292 295 private int addInstructionToDocument(AbstractInstruction instruction) 296 throws InvalidByteCodeException { 297 298 int offset = instruction.getOffset(); 299 300 301 appendString(getPaddedValue(offset, offsetWidth)); 302 303 appendString(" " + instruction.getOpcodeVerbose()); 304 305 int additionalLines = addOpcodeSpecificInfo(instruction); 306 307 appendString("\n"); 308 309 return additionalLines + 1; 310 } 311 312 315 private int addOpcodeSpecificInfo(AbstractInstruction instruction) 316 throws InvalidByteCodeException { 317 318 int additionalLines = 0; 319 320 if (instruction instanceof ImmediateByteInstruction) { 321 additionalLines += 322 addImmediateByteSpecificInfo((ImmediateByteInstruction)instruction); 323 } else if (instruction instanceof ImmediateShortInstruction) { 324 additionalLines += 325 addImmediateShortSpecificInfo((ImmediateShortInstruction)instruction); 326 } else if (instruction instanceof ImmediateIntInstruction) { 327 additionalLines += 328 addImmediateIntSpecificInfo((ImmediateIntInstruction)instruction); 329 } else if (instruction instanceof BranchInstruction) { 330 additionalLines += 331 addBranchSpecificInfo((BranchInstruction)instruction); 332 } else if (instruction instanceof TableSwitchInstruction) { 333 additionalLines += 334 addTableSwitchSpecificInfo((TableSwitchInstruction)instruction); 335 } else if (instruction instanceof LookupSwitchInstruction) { 336 additionalLines += 337 addLookupSwitchSpecificInfo((LookupSwitchInstruction)instruction); 338 } 339 340 return additionalLines; 341 } 342 343 346 private int addImmediateByteSpecificInfo(ImmediateByteInstruction instruction) 347 throws InvalidByteCodeException { 348 349 int opcode = instruction.getOpcode(); 350 int sourceOffset = instruction.getOffset(); 351 int immediateByte = instruction.getImmediateByte(); 352 353 if (opcode == OPCODE_LDC) { 354 addConstantPoolLink(immediateByte, sourceOffset); 355 } else if (opcode == OPCODE_NEWARRAY) { 356 String verbose = OpcodesUtil.getArrayTypeVerbose(immediateByte); 357 appendString(" " + immediateByte + " (" + verbose + ")"); 358 359 } else { 360 appendString(" " + immediateByte); 361 362 if (instruction instanceof IncrementInstruction) { 363 appendString(" by"); 364 appendString(" " + ((IncrementInstruction)instruction).getIncrementConst()); 365 } 366 } 367 return 0; 368 } 369 370 373 private int addImmediateShortSpecificInfo(ImmediateShortInstruction instruction) 374 throws InvalidByteCodeException { 375 376 int opcode = instruction.getOpcode(); 377 int sourceOffset = instruction.getOffset(); 378 int immediateShort = instruction.getImmediateShort(); 379 380 if (opcode == OPCODE_SIPUSH) { 381 appendString(" " + immediateShort); 382 } else { 383 addConstantPoolLink(immediateShort, sourceOffset); 384 385 if (instruction instanceof InvokeInterfaceInstruction) { 386 appendString(" count " + ((InvokeInterfaceInstruction)instruction).getCount()); 387 388 } else if (instruction instanceof MultianewarrayInstruction) { 389 appendString(" dim " + ((MultianewarrayInstruction)instruction).getDimensions()); 390 391 } 392 } 393 394 return 0; 395 } 396 397 400 private int addImmediateIntSpecificInfo(ImmediateIntInstruction instruction) 401 throws InvalidByteCodeException { 402 403 int immediateInt = instruction.getImmediateInt(); 404 int sourceOffset = instruction.getOffset(); 405 406 addConstantPoolLink(immediateInt, sourceOffset); 407 408 return 0; 409 } 410 411 414 private int addBranchSpecificInfo(BranchInstruction instruction) { 415 416 int branchOffset = instruction.getBranchOffset(); 417 int instructionOffset = instruction.getOffset(); 418 419 addOffsetLink(branchOffset, instructionOffset); 420 421 return 0; 422 } 423 424 427 private int addTableSwitchSpecificInfo(TableSwitchInstruction instruction) { 428 429 int instructionOffset = instruction.getOffset(); 430 int lowByte = instruction.getLowByte(); 431 int highByte = instruction.getHighByte(); 432 int[] jumpOffsets = instruction.getJumpOffsets(); 433 434 appendString(" " + lowByte + " to " + highByte + "\n"); 435 436 for (int i = 0; i <= highByte - lowByte; i++) { 437 appendString("\u0009" + (i + lowByte) + ": " ); 438 addOffsetLink(jumpOffsets[i], instructionOffset); 439 appendString("\n" ); 440 441 } 442 appendString("\u0009default: " ); 443 addOffsetLink(instruction.getDefaultOffset(), instructionOffset); 444 445 return highByte - lowByte + 2; 446 } 447 448 451 private int addLookupSwitchSpecificInfo(LookupSwitchInstruction instruction) { 452 453 int instructionOffset = instruction.getOffset(); 454 java.util.List matchOffsetPairs = instruction.getMatchOffsetPairs(); 455 int matchOffsetPairsCount = matchOffsetPairs.size(); 456 457 appendString(" " + matchOffsetPairsCount + "\n"); 458 459 MatchOffsetPair matchOffsetPairEntry; 460 461 for (int i = 0; i < matchOffsetPairsCount; i++) { 462 matchOffsetPairEntry = (MatchOffsetPair)matchOffsetPairs.get(i); 463 appendString("\u0009" + matchOffsetPairEntry.getMatch() + ": "); 464 addOffsetLink(matchOffsetPairEntry.getOffset(), instructionOffset); 465 appendString("\n" ); 466 467 } 468 appendString("\u0009default: "); 469 addOffsetLink(instruction.getDefaultOffset(), instructionOffset); 470 471 return matchOffsetPairsCount + 1; 472 } 473 474 477 private void addConstantPoolLink(int constantPoolIndex, int sourceOffset) 478 throws InvalidByteCodeException { 479 480 appendString(I_CALL,"#" + constantPoolIndex); 481 482 String name = classFile.getConstantPoolEntryName(constantPoolIndex); 483 if (name.length() > 0) { 484 appendString(" <" + name + ">"); 485 } 486 487 } 488 489 492 private void addOffsetLink(int branchOffset, int instructionOffset) { 493 494 int totalOffset = branchOffset + instructionOffset; 495 496 appendString(String.valueOf(totalOffset)); 497 498 appendString(" (" + (branchOffset > 0 ? "+" : "") 499 + String.valueOf(branchOffset) + ")"); 500 } 501 502 503 504 507 private void createOpcodeCounterDocument(int[] linesPerOpcode) { 508 509 510 int numberOfOpcodes = linesPerOpcode.length; 511 512 opcodeCounterWidth = String.valueOf(numberOfOpcodes - 1).length(); 513 514 515 for (int i = 0; i < numberOfOpcodes; i++) { 516 appendString(getPaddedValue(i, opcodeCounterWidth)); 517 518 for (int j = 0; j < linesPerOpcode[i]; j++) { 519 appendString("\n"); 520 } 521 } 522 523 524 } 525 526 532 private static String getPaddedValue(int number, int width) { 533 534 StringBuffer buffer = new StringBuffer (); 535 String value = String.valueOf(number); 536 int valueLength = value.length(); 537 for (int i = valueLength; i < width; i++) { 538 buffer.append(' '); 539 } 540 buffer.append(value); 541 return buffer.toString(); 542 } 543 544 551 private boolean doubleCheckCalledMethod(int instructionReference) { 552 553 554 String previousInstruction = (String )internalInstructions.get(String.valueOf(instructionReference-1)); 556 557 if (previousInstruction == null) { 559 return false; 560 } 561 562 if(previousInstruction.indexOf("invoke")>-1) { 564 return true; 565 } else { 566 return false; 567 } 568 569 } 570 571 576 private String getClassFromCalledString(String inString){ 577 578 String returnString=""; 579 580 int breakplace = inString.lastIndexOf("."); 582 583 returnString = inString.substring(0,breakplace); 585 586 returnString = tidyNames(returnString); 587 588 589 return returnString; 590 } 591 592 597 private String getMethodFromCalledString(String inString){ 598 599 String returnString=""; 600 601 int breakplace = inString.lastIndexOf("."); 603 604 returnString = inString.substring(breakplace,inString.length()); 606 607 returnString =tidyNames(returnString); 608 609 return returnString; 610 } 611 612 } 613 614 615 616 617 | Popular Tags |