1 21 package proguard.classfile.editor; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.preverification.visitor.*; 26 import proguard.classfile.attribute.preverification.*; 27 import proguard.classfile.attribute.visitor.*; 28 import proguard.classfile.instruction.*; 29 import proguard.classfile.instruction.visitor.InstructionVisitor; 30 import proguard.classfile.util.SimplifiedVisitor; 31 32 38 public class CodeAttributeComposer 39 extends SimplifiedVisitor 40 implements AttributeVisitor, 41 InstructionVisitor, 42 ExceptionInfoVisitor, 43 StackMapFrameVisitor, 44 VerificationTypeVisitor, 45 LineNumberInfoVisitor, 46 LocalVariableInfoVisitor, 47 LocalVariableTypeInfoVisitor 48 { 49 private static final boolean DEBUG = false; 51 54 55 56 private static final int MAXIMUM_LEVELS = 32; 57 58 59 private int maximumCodeLength; 60 private int codeLength; 61 private int exceptionTableLength; 62 private int level = -1; 63 64 private byte[] code = new byte[ClassConstants.TYPICAL_CODE_LENGTH]; 65 private int[] oldInstructionOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; 66 private int[] codeFragmentOffsets = new int[MAXIMUM_LEVELS]; 67 private int[] codeFragmentLengths = new int[MAXIMUM_LEVELS]; 68 private int[][] instructionOffsetMap = new int[MAXIMUM_LEVELS][ClassConstants.TYPICAL_CODE_LENGTH]; 69 70 private ExceptionInfo[] exceptionTable = new ExceptionInfo[ClassConstants.TYPICAL_EXCEPTION_TABLE_LENGTH]; 71 72 private int expectedStackMapFrameOffset; 73 74 private StackSizeUpdater stackSizeUpdater = new StackSizeUpdater(); 75 private VariableSizeUpdater variableSizeUpdater = new VariableSizeUpdater(); 76 77 78 81 public void reset() 82 { 83 maximumCodeLength = 0; 84 codeLength = 0; 85 exceptionTableLength = 0; 86 level = -1; 87 } 88 89 90 96 public void beginCodeFragment(int maximumCodeFragmentLength) 97 { 98 level++; 99 100 if (level >= MAXIMUM_LEVELS) 101 { 102 throw new IllegalArgumentException ("Maximum number of code fragment levels exceeded ["+level+"]"); 103 } 104 105 maximumCodeLength += maximumCodeFragmentLength; 107 if (code.length < maximumCodeLength) 108 { 109 byte[] newCode = new byte[maximumCodeLength]; 110 System.arraycopy(code, 0, newCode, 0, codeLength); 111 code = newCode; 112 113 int[] newOldInstructionOffsets = new int[maximumCodeLength]; 114 System.arraycopy(oldInstructionOffsets, 0, newOldInstructionOffsets, 0, codeLength); 115 oldInstructionOffsets = newOldInstructionOffsets; 116 } 117 118 if (instructionOffsetMap[level].length <= maximumCodeFragmentLength) 120 { 121 instructionOffsetMap[level] = new int[maximumCodeFragmentLength + 1]; 122 } 123 124 codeFragmentOffsets[level] = codeLength; 126 codeFragmentLengths[level] = maximumCodeFragmentLength; 127 } 128 129 130 137 public void appendInstruction(int oldInstructionOffset, 138 Instruction instruction) 139 { 140 if (DEBUG) 141 { 142 println("["+codeLength+"] <- ", instruction.toString(oldInstructionOffset)); 143 } 144 145 oldInstructionOffsets[codeLength] = oldInstructionOffset; 147 148 instruction.write(code, codeLength); 150 151 instructionOffsetMap[level][oldInstructionOffset] = codeLength; 153 154 codeLength += instruction.length(codeLength); 156 } 157 158 159 165 public void appendLabel(int oldInstructionOffset) 166 { 167 if (DEBUG) 168 { 169 println("["+codeLength+"] <- ", "[" + oldInstructionOffset + "] (label)"); 170 } 171 172 instructionOffsetMap[level][oldInstructionOffset] = codeLength; 174 } 175 176 177 181 public void appendException(ExceptionInfo exceptionInfo) 182 { 183 if (DEBUG) 184 { 185 print(" ", "Exception ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+": "+exceptionInfo.u2handlerPC+"]"); 186 } 187 188 visitExceptionInfo(null, null, null, exceptionInfo); 190 191 if (DEBUG) 192 { 193 System.out.println(" -> ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+": "+exceptionInfo.u2handlerPC+"]"); 194 } 195 196 if (exceptionInfo.u2startPC == exceptionInfo.u2endPC) 198 { 199 if (DEBUG) 200 { 201 println(" ", " (not added because of empty instruction range)"); 202 } 203 204 return; 205 } 206 207 if (exceptionTable.length <= exceptionTableLength) 209 { 210 ExceptionInfo[] newExceptionTable = new ExceptionInfo[exceptionTableLength+1]; 211 System.arraycopy(exceptionTable, 0, newExceptionTable, 0, exceptionTableLength); 212 exceptionTable = newExceptionTable; 213 } 214 215 exceptionTable[exceptionTableLength++] = exceptionInfo; 217 } 218 219 220 224 public void endCodeFragment() 225 { 226 if (level < 0) 227 { 228 throw new IllegalArgumentException ("Code fragment not begun ["+level+"]"); 229 } 230 231 int instructionOffset = codeFragmentOffsets[level]; 233 while (instructionOffset < codeLength) 234 { 235 Instruction instruction = InstructionFactory.create(code, instructionOffset); 237 238 if (oldInstructionOffsets[instructionOffset] >= 0) 240 { 241 instruction.accept(null, null, null, instructionOffset, this); 243 244 instruction.write(code, instructionOffset); 246 247 oldInstructionOffsets[instructionOffset] = -1; 249 } 250 251 instructionOffset += instruction.length(instructionOffset); 253 } 254 255 maximumCodeLength += codeLength - codeFragmentOffsets[level] - 258 codeFragmentLengths[level]; 259 260 level--; 261 } 262 263 264 266 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 267 268 269 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 270 { 271 if (DEBUG) 272 { 273 System.out.println("CodeAttributeComposer: putting results in ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 274 } 275 276 if (level != -1) 277 { 278 throw new IllegalArgumentException ("Code fragment not ended ["+level+"]"); 279 } 280 281 level++; 282 283 if (codeAttribute.u4codeLength < codeLength) 286 { 287 codeAttribute.code = new byte[codeLength]; 288 } 289 290 codeAttribute.u4codeLength = codeLength; 292 System.arraycopy(code, 0, codeAttribute.code, 0, codeLength); 293 294 298 if (codeAttribute.exceptionTable.length < exceptionTableLength) 301 { 302 codeAttribute.exceptionTable = new ExceptionInfo[exceptionTableLength]; 303 } 304 305 codeAttribute.u2exceptionTableLength = exceptionTableLength; 307 System.arraycopy(exceptionTable, 0, codeAttribute.exceptionTable, 0, exceptionTableLength); 308 309 stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); 311 variableSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); 312 313 codeAttribute.attributesAccept(clazz, method, this); 315 316 319 324 level--; 325 } 326 327 328 public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) 329 { 330 expectedStackMapFrameOffset = -1; 332 stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); 333 } 334 335 336 public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) 337 { 338 expectedStackMapFrameOffset = 0; 340 stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); 341 } 342 343 344 public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) 345 { 346 lineNumberTableAttribute.lineNumbersAccept(clazz, method, codeAttribute, this); 348 349 lineNumberTableAttribute.u2lineNumberTableLength = 351 removeEmptyLineNumbers(lineNumberTableAttribute.lineNumberTable, 352 lineNumberTableAttribute.u2lineNumberTableLength, 353 codeAttribute.u4codeLength); 354 } 355 356 357 public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) 358 { 359 localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 361 362 localVariableTableAttribute.u2localVariableTableLength = 364 removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, 365 localVariableTableAttribute.u2localVariableTableLength, 366 codeAttribute.u2maxLocals); 367 } 368 369 370 public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) 371 { 372 localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 374 375 localVariableTypeTableAttribute.u2localVariableTypeTableLength = 377 removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, 378 localVariableTypeTableAttribute.u2localVariableTypeTableLength, 379 codeAttribute.u2maxLocals); 380 } 381 382 383 385 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 386 387 388 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 389 { 390 branchInstruction.branchOffset = remapBranchOffset(offset, 392 branchInstruction.branchOffset); 393 } 394 395 396 public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) 397 { 398 switchInstruction.defaultOffset = remapBranchOffset(offset, 400 switchInstruction.defaultOffset); 401 402 remapJumpOffsets(offset, 404 switchInstruction.jumpOffsets); 405 } 406 407 408 410 public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 411 { 412 exceptionInfo.u2startPC = remapInstructionOffset(exceptionInfo.u2startPC); 415 exceptionInfo.u2endPC = remapInstructionOffset(exceptionInfo.u2endPC); 416 exceptionInfo.u2handlerPC = remapInstructionOffset(exceptionInfo.u2handlerPC); 417 } 418 419 420 422 public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) 423 { 424 int stackMapFrameOffset = remapInstructionOffset(offset); 426 427 int offsetDelta = stackMapFrameOffset; 428 429 if (expectedStackMapFrameOffset >= 0) 432 { 433 offsetDelta -= expectedStackMapFrameOffset; 434 435 expectedStackMapFrameOffset = stackMapFrameOffset + 1; 436 } 437 438 stackMapFrame.u2offsetDelta = offsetDelta; 439 } 440 441 442 public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) 443 { 444 visitAnyStackMapFrame(clazz, method, codeAttribute, offset, sameOneFrame); 446 447 sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); 449 } 450 451 452 public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) 453 { 454 visitAnyStackMapFrame(clazz, method, codeAttribute, offset, moreZeroFrame); 456 457 moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); 459 } 460 461 462 public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) 463 { 464 visitAnyStackMapFrame(clazz, method, codeAttribute, offset, fullFrame); 466 467 fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); 469 fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); 470 } 471 472 473 475 public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} 476 477 478 public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType) 479 { 480 uninitializedType.u2newInstructionOffset = remapInstructionOffset(uninitializedType.u2newInstructionOffset); 482 } 483 484 485 487 public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo) 488 { 489 lineNumberInfo.u2startPC = remapInstructionOffset(lineNumberInfo.u2startPC); 491 } 492 493 494 496 public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) 497 { 498 int startPC = remapInstructionOffset(localVariableInfo.u2startPC); 501 int endPC = remapInstructionOffset(localVariableInfo.u2startPC + localVariableInfo.u2length); 502 503 localVariableInfo.u2startPC = startPC; 504 localVariableInfo.u2length = endPC - startPC; 505 } 506 507 509 public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) 510 { 511 int startPC = remapInstructionOffset(localVariableTypeInfo.u2startPC); 514 int endPC = remapInstructionOffset(localVariableTypeInfo.u2startPC + localVariableTypeInfo.u2length); 515 516 localVariableTypeInfo.u2length = startPC; 517 localVariableTypeInfo.u2startPC = endPC - startPC; 518 } 519 520 521 523 526 private void remapJumpOffsets(int offset, int[] jumpOffsets) 527 { 528 for (int index = 0; index < jumpOffsets.length; index++) 529 { 530 jumpOffsets[index] = remapBranchOffset(offset, jumpOffsets[index]); 531 } 532 } 533 534 535 539 private int remapBranchOffset(int newInstructionOffset, int branchOffset) 540 { 541 if (newInstructionOffset < 0 || 542 newInstructionOffset > codeLength) 543 { 544 throw new IllegalArgumentException ("Invalid instruction offset ["+newInstructionOffset +"] in code with length ["+codeLength+"]"); 545 } 546 547 int oldInstructionOffset = oldInstructionOffsets[newInstructionOffset]; 548 549 return remapInstructionOffset(oldInstructionOffset + branchOffset) - 550 remapInstructionOffset(oldInstructionOffset); 551 } 552 553 554 558 private int remapInstructionOffset(int oldInstructionOffset) 559 { 560 if (oldInstructionOffset < 0 || 561 oldInstructionOffset > codeFragmentLengths[level]) 562 { 563 throw new IllegalArgumentException ("Invalid instruction offset ["+oldInstructionOffset +"] in code fragment with length ["+codeFragmentLengths[level]+"]"); 564 } 565 566 return instructionOffsetMap[level][oldInstructionOffset]; 567 } 568 569 570 574 private int removeEmptyExceptions(ExceptionInfo[] exceptionInfos, 575 int exceptionInfoCount) 576 { 577 int newIndex = 0; 579 for (int index = 0; index < exceptionInfoCount; index++) 580 { 581 ExceptionInfo exceptionInfo = exceptionInfos[index]; 582 if (exceptionInfo.u2startPC < exceptionInfo.u2endPC) 583 { 584 exceptionInfos[newIndex++] = exceptionInfo; 585 } 586 } 587 588 for (int index = newIndex; index < exceptionInfoCount; index++) 590 { 591 exceptionInfos[index] = null; 592 } 593 594 return newIndex; 595 } 596 597 598 602 private int removeEmptyLineNumbers(LineNumberInfo[] lineNumberInfos, 603 int lineNumberInfoCount, 604 int codeLength) 605 { 606 int newIndex = 0; 608 for (int index = 0; index < lineNumberInfoCount; index++) 609 { 610 LineNumberInfo lineNumberInfo = lineNumberInfos[index]; 611 int startPC = lineNumberInfo.u2startPC; 612 if (startPC < codeLength && 613 (index == 0 || startPC > lineNumberInfos[index-1].u2startPC)) 614 { 615 lineNumberInfos[newIndex++] = lineNumberInfo; 616 } 617 } 618 619 for (int index = newIndex; index < lineNumberInfoCount; index++) 621 { 622 lineNumberInfos[index] = null; 623 } 624 625 return newIndex; 626 } 627 628 629 633 private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, 634 int localVariableInfoCount, 635 int maxLocals) 636 { 637 int newIndex = 0; 639 for (int index = 0; index < localVariableInfoCount; index++) 640 { 641 LocalVariableInfo localVariableInfo = localVariableInfos[index]; 642 if (localVariableInfo.u2length > 0 && 643 localVariableInfo.u2index < maxLocals) 644 { 645 localVariableInfos[newIndex++] = localVariableInfo; 646 } 647 } 648 649 for (int index = newIndex; index < localVariableInfoCount; index++) 651 { 652 localVariableInfos[index] = null; 653 } 654 655 return newIndex; 656 } 657 658 659 663 private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, 664 int localVariableTypeInfoCount, 665 int maxLocals) 666 { 667 int newIndex = 0; 669 for (int index = 0; index < localVariableTypeInfoCount; index++) 670 { 671 LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; 672 if (localVariableTypeInfo.u2length > 0 && 673 localVariableTypeInfo.u2index < maxLocals) 674 { 675 localVariableTypeInfos[newIndex++] = localVariableTypeInfo; 676 } 677 } 678 679 for (int index = newIndex; index < localVariableTypeInfoCount; index++) 681 { 682 localVariableTypeInfos[index] = null; 683 } 684 685 return newIndex; 686 } 687 688 689 private void println(String string1, String string2) 690 { 691 print(string1, string2); 692 693 System.out.println(); 694 } 695 696 private void print(String string1, String string2) 697 { 698 System.out.print(string1); 699 700 for (int index = 0; index < level; index++) 701 { 702 System.out.print(" "); 703 } 704 705 System.out.print(string2); 706 } 707 708 709 public static void main(String [] args) 710 { 711 CodeAttributeComposer composer = new CodeAttributeComposer(); 712 713 composer.beginCodeFragment(10); 714 composer.appendInstruction(0, new SimpleInstruction(InstructionConstants.OP_ICONST_0)); 715 composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ISTORE, 0)); 716 composer.appendInstruction(2, new BranchInstruction(InstructionConstants.OP_GOTO, 1)); 717 718 composer.beginCodeFragment(10); 719 composer.appendInstruction(0, new VariableInstruction(InstructionConstants.OP_IINC, 0, 1)); 720 composer.appendInstruction(1, new VariableInstruction(InstructionConstants.OP_ILOAD, 0)); 721 composer.appendInstruction(2, new SimpleInstruction(InstructionConstants.OP_ICONST_5)); 722 composer.appendInstruction(3, new BranchInstruction(InstructionConstants.OP_IFICMPLT, -3)); 723 composer.endCodeFragment(); 724 725 composer.appendInstruction(3, new SimpleInstruction(InstructionConstants.OP_RETURN)); 726 composer.endCodeFragment(); 727 } 728 } 729 | Popular Tags |