1 19 20 package jode.obfuscator.modules; 21 22 import jode.AssertError; 23 import jode.GlobalOptions; 24 import jode.bytecode.*; 25 import jode.jvm.InterpreterException; 26 import jode.obfuscator.*; 27 28 import java.lang.reflect.Array ; 29 import java.lang.reflect.Modifier ; 30 import java.lang.reflect.InvocationTargetException ; 31 import java.util.BitSet ; 32 33 import java.util.Arrays ; 34 import java.util.Collection ; 35 import java.util.HashSet ; 36 import java.util.Set ; 37 import java.util.HashMap ; 38 import java.util.Map ; 39 import java.util.Iterator ; 40 import java.util.ListIterator ; 41 42 48 public class ConstantAnalyzer extends SimpleAnalyzer 49 implements Opcodes, CodeAnalyzer { 50 51 BytecodeInfo bytecode; 52 53 private static ConstantRuntimeEnvironment runtime 54 = new ConstantRuntimeEnvironment(); 55 56 private final static int CMP_EQ = 0; 57 private final static int CMP_NE = 1; 58 private final static int CMP_LT = 2; 59 private final static int CMP_GE = 3; 60 private final static int CMP_GT = 4; 61 private final static int CMP_LE = 5; 62 private final static int CMP_GREATER_MASK 63 = (1 << CMP_GT)|(1 << CMP_GE)|(1 << CMP_NE); 64 private final static int CMP_LESS_MASK 65 = (1 << CMP_LT)|(1 << CMP_LE)|(1 << CMP_NE); 66 private final static int CMP_EQUAL_MASK 67 = (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ); 68 69 final static int CONSTANT = 0x02; 70 final static int CONSTANTFLOW = 0x04; 71 final static int RETASTORE = 0x08; 72 final static int RETURNINGJSR = 0x10; 73 74 private interface ConstantListener { 75 public void constantChanged(); 76 } 77 78 private final static class JSRTargetInfo implements Cloneable { 79 Instruction jsrTarget; 80 BitSet usedLocals; 81 82 87 Object dependent; 88 89 public JSRTargetInfo(Instruction target) { 90 jsrTarget = target; 91 usedLocals = new BitSet (); 92 } 93 94 public JSRTargetInfo copy() { 95 try { 96 JSRTargetInfo result = (JSRTargetInfo) clone(); 97 result.usedLocals = (BitSet ) usedLocals.clone(); 98 addDependent(result); 99 return result; 100 } catch (CloneNotSupportedException ex) { 101 throw new IncompatibleClassChangeError (ex.getMessage()); 102 } 103 } 104 105 private void addDependent(JSRTargetInfo result) { 106 if (dependent == null || dependent == result) 107 dependent = result; 108 else if (dependent instanceof JSRTargetInfo) { 109 Set newDeps = new HashSet (); 110 newDeps.add(dependent); 111 newDeps.add(result); 112 } else if (dependent instanceof Collection ) { 113 ((Collection ) dependent).add(result); 114 } 115 } 116 117 public void setRetInfo(StackLocalInfo retInfo) { 118 dependent = retInfo; 119 } 120 121 public boolean uses(int localSlot) { 122 return usedLocals.get(localSlot); 123 } 124 125 public void addUsed(int localSlot) { 126 if (usedLocals.get(localSlot)) 127 return; 128 usedLocals.set(localSlot); 129 130 if (dependent instanceof StackLocalInfo) 131 ((StackLocalInfo) dependent).enqueue(); 132 else if (dependent instanceof JSRTargetInfo) 133 ((JSRTargetInfo) dependent).addUsed(localSlot); 134 else if (dependent instanceof Collection ) { 135 Iterator iter = ((Collection ) dependent).iterator(); 136 while (iter.hasNext()) { 137 JSRTargetInfo dep = (JSRTargetInfo) iter.next(); 138 dep.addUsed(localSlot); 139 } 140 } 141 } 142 143 public void merge(JSRTargetInfo o) { 144 o.addDependent(this); 145 for (int slot = 0; slot < o.usedLocals.size(); slot++) { 146 if (o.usedLocals.get(slot)) 147 addUsed(slot); 148 } 149 } 150 151 public String toString() { 152 StringBuffer sb = new StringBuffer (String.valueOf(jsrTarget)); 153 if (dependent instanceof StackLocalInfo) 154 sb.append("->").append(((StackLocalInfo) dependent).instr); 155 return sb.append(usedLocals) 156 .append('_').append(hashCode()).toString(); 157 } 158 } 159 160 private static class ConstValue implements ConstantListener { 161 public final static Object VOLATILE = new Object (); 162 166 Object value; 167 170 int stackSize; 171 175 Set listeners; 176 177 public ConstValue(Object constant) { 178 value = constant; 179 stackSize = (constant instanceof Double 180 || constant instanceof Long ) ? 2 : 1; 181 listeners = new HashSet (); 182 } 183 184 public ConstValue(ConstValue constant) { 185 value = constant.value; 186 stackSize = constant.stackSize; 187 listeners = new HashSet (); 188 constant.addConstantListener(this); 189 } 190 191 public ConstValue(int stackSize) { 192 this.value = VOLATILE; 193 this.stackSize = stackSize; 194 } 195 196 public ConstValue copy() { 197 return (value == VOLATILE) ? this 198 : new ConstValue(this); 199 } 200 201 public void addConstantListener(ConstantListener l) { 202 listeners.add(l); 203 } 204 205 public void removeConstantListener(ConstantListener l) { 206 listeners.remove(l); 207 } 208 209 public void fireChanged() { 210 value = VOLATILE; 211 for (Iterator i = listeners.iterator(); i.hasNext(); ) 212 ((ConstantListener) i.next()).constantChanged(); 213 listeners = null; 214 } 215 216 public void constantChanged() { 217 if (value != VOLATILE) 218 fireChanged(); 219 } 220 221 224 public void merge(ConstValue other) { 225 if (this == other) 226 return; 227 228 if (value == null ? other.value == null 229 : value.equals(other.value)) { 230 if (value != VOLATILE) { 231 other.addConstantListener(this); 232 this.addConstantListener(other); 233 } 234 return; 235 } 236 237 if (value instanceof JSRTargetInfo 238 && other.value instanceof JSRTargetInfo 239 && (((JSRTargetInfo) value).jsrTarget 240 == ((JSRTargetInfo) other.value).jsrTarget)) { 241 ((JSRTargetInfo) value).merge((JSRTargetInfo) other.value); 242 return; 243 } 244 245 if (value != VOLATILE) 246 fireChanged(); 247 } 250 251 public String toString() { 252 return value == VOLATILE ? "vol("+stackSize+")" : ""+value; 253 } 254 } 255 256 private static class TodoQueue { 257 StackLocalInfo first; 258 } 259 260 private static class StackLocalInfo implements ConstantListener { 261 ConstValue[] stack; 262 ConstValue[] locals; 263 Instruction instr; 264 ConstantInfo constInfo; 265 StackLocalInfo retInfo; 266 267 StackLocalInfo nextOnQueue; 268 269 274 TodoQueue notifyQueue; 275 276 public ConstValue copy(ConstValue value) { 277 return (value == null) ? null : value.copy(); 278 } 279 280 private StackLocalInfo(ConstValue[] stack, 281 ConstValue[] locals, 282 TodoQueue notifyQueue) { 283 this.stack = stack; 284 this.locals = new ConstValue[locals.length]; 285 for (int i=0; i< locals.length; i++) 286 this.locals[i] = copy(locals[i]); 287 this.notifyQueue = notifyQueue; 288 } 289 290 public StackLocalInfo(int numLocals, 291 boolean isStatic, String methodTypeSig, 292 TodoQueue notifyQueue) { 293 294 String [] paramTypes 295 = TypeSignature.getParameterTypes(methodTypeSig); 296 locals = new ConstValue[numLocals]; 297 stack = new ConstValue[0]; 298 this.notifyQueue = notifyQueue; 299 int slot = 0; 300 if (!isStatic) 301 locals[slot++] = new ConstValue(1); 302 for (int i=0; i< paramTypes.length; i++) { 303 int stackSize = TypeSignature.getTypeSize(paramTypes[i]); 304 locals[slot] = unknownValue[stackSize-1]; 305 slot += stackSize; 306 } 307 } 308 309 public final void enqueue() { 310 if (nextOnQueue == null) { 311 this.nextOnQueue = notifyQueue.first; 312 notifyQueue.first = this; 313 } 314 } 315 316 public void constantChanged() { 317 enqueue(); 318 } 319 320 public StackLocalInfo poppush(int pops, ConstValue push) { 321 ConstValue[] newStack 322 = new ConstValue[stack.length - pops + push.stackSize]; 323 ConstValue[] newLocals = (ConstValue[]) locals.clone(); 324 System.arraycopy(stack, 0, newStack, 0, stack.length-pops); 325 newStack[stack.length-pops] = push.copy(); 326 return new StackLocalInfo(newStack, newLocals, notifyQueue); 327 } 328 329 public StackLocalInfo pop(int pops) { 330 ConstValue[] newStack 331 = new ConstValue[stack.length - pops]; 332 ConstValue[] newLocals = (ConstValue[]) locals.clone(); 333 System.arraycopy(stack, 0, newStack, 0, stack.length-pops); 334 return new StackLocalInfo(newStack, newLocals, notifyQueue); 335 } 336 337 public StackLocalInfo dup(int count, int depth) { 338 ConstValue[] newStack 339 = new ConstValue[stack.length + count]; 340 ConstValue[] newLocals = (ConstValue[]) locals.clone(); 341 if (depth == 0) 342 System.arraycopy(stack, 0, newStack, 0, stack.length); 343 else { 344 int pos = stack.length - count - depth; 345 System.arraycopy(stack, 0, newStack, 0, pos); 346 for (int i=0; i < count; i++) 347 newStack[pos++] = copy(stack[stack.length-count + i]); 348 for (int i=0; i < depth; i++) 349 newStack[pos++] = copy(stack[stack.length-count-depth + i]); 350 } 351 for (int i=0; i < count; i++) 352 newStack[stack.length+i] = copy(stack[stack.length-count + i]); 353 return new StackLocalInfo(newStack, newLocals, notifyQueue); 354 } 355 356 public StackLocalInfo swap() { 357 ConstValue[] newStack 358 = new ConstValue[stack.length]; 359 ConstValue[] newLocals = (ConstValue[]) locals.clone(); 360 System.arraycopy(stack, 0, newStack, 0, stack.length - 2); 361 newStack[stack.length-2] = stack[stack.length-1].copy(); 362 newStack[stack.length-1] = stack[stack.length-2].copy(); 363 return new StackLocalInfo(newStack, newLocals, notifyQueue); 364 } 365 366 public StackLocalInfo copy() { 367 ConstValue[] newStack = (ConstValue[]) stack.clone(); 368 ConstValue[] newLocals = (ConstValue[]) locals.clone(); 369 return new StackLocalInfo(newStack, newLocals, notifyQueue); 370 } 371 372 public ConstValue getLocal(int slot) { 373 return locals[slot]; 374 } 375 376 public ConstValue getStack(int depth) { 377 return stack[stack.length - depth]; 378 } 379 380 public StackLocalInfo setLocal(int slot, ConstValue value) { 381 locals[slot] = value; 382 if (value != null && value.stackSize == 2) 383 locals[slot+1] = null; 384 for (int i=0; i< locals.length; i++) { 385 if (locals[i] != null 386 && locals[i].value instanceof JSRTargetInfo) { 387 JSRTargetInfo jsrInfo = (JSRTargetInfo)locals[i].value; 388 if (!jsrInfo.uses(slot)) { 389 jsrInfo = jsrInfo.copy(); 390 locals[i] = locals[i].copy(); 391 locals[i].value = jsrInfo; 392 jsrInfo.addUsed(slot); 393 } 394 } 395 } 396 for (int i=0; i< stack.length; i++) { 397 if (stack[i] != null 398 && stack[i].value instanceof JSRTargetInfo) { 399 JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value; 400 if (!jsrInfo.uses(slot)) { 401 jsrInfo = jsrInfo.copy(); 402 stack[i] = stack[i].copy(); 403 stack[i].value = jsrInfo; 404 jsrInfo.addUsed(slot); 405 } 406 } 407 } 408 return this; 409 } 410 411 public StackLocalInfo mergeRetLocals(JSRTargetInfo jsrTargetInfo, 412 StackLocalInfo retInfo) { 413 for (int slot = 0; slot < locals.length; slot++) { 414 if (jsrTargetInfo.uses(slot)) 415 locals[slot] = retInfo.locals[slot]; 416 } 417 locals[retInfo.instr.getLocalSlot()] = null; 418 419 for (int i=0; i< locals.length; i++) { 420 if (locals[i] != null 421 && locals[i].value instanceof JSRTargetInfo) { 422 JSRTargetInfo jsrInfo = (JSRTargetInfo) locals[i].value; 423 jsrInfo = jsrInfo.copy(); 424 locals[i] = locals[i].copy(); 425 locals[i].value = jsrInfo; 426 for (int slot = 0; slot < locals.length; slot++) { 427 if (jsrTargetInfo.uses(slot)) 428 jsrInfo.addUsed(slot); 429 } 430 } 431 } 432 for (int i=0; i< stack.length; i++) { 433 if (stack[i] != null 434 && stack[i].value instanceof JSRTargetInfo) { 435 JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value; 436 jsrInfo = jsrInfo.copy(); 437 stack[i] = stack[i].copy(); 438 stack[i].value = jsrInfo; 439 for (int slot = 0; slot < locals.length; slot++) { 440 if (jsrTargetInfo.uses(slot)) 441 jsrInfo.addUsed(slot); 442 } 443 } 444 } 445 return this; 446 } 447 448 public void merge(StackLocalInfo other) { 449 for (int i=0; i < locals.length; i++) { 450 if (locals[i] != null) { 451 if (other.locals[i] == null) { 452 locals[i].constantChanged(); 453 locals[i] = null; 454 enqueue(); 455 } else { 456 locals[i].merge(other.locals[i]); 457 } 458 } 459 } 460 if (stack.length != other.stack.length) 461 throw new jode.AssertError("stack length differs"); 462 for (int i=0; i < stack.length; i++) { 463 if ((other.stack[i] == null) != (stack[i] == null)) 464 throw new jode.AssertError("stack types differ"); 465 else if (stack[i] != null) 466 stack[i].merge(other.stack[i]); 467 } 468 } 469 470 public String toString() { 471 return "Locals: "+Arrays.asList(locals) 472 +"Stack: "+Arrays.asList(stack)+ "Instr: "+instr; 473 } 474 } 475 476 private static class ConstantInfo implements ConstantListener { 477 ConstantInfo() { 478 this(0, null); 479 } 480 481 ConstantInfo(int flags) { 482 this(flags, null); 483 } 484 485 ConstantInfo(int flags, Object constant) { 486 this.flags = flags; 487 this.constant = constant; 488 } 489 490 int flags; 491 494 Object constant; 495 496 public void constantChanged() { 497 constant = null; 498 flags &= ~(CONSTANT | CONSTANTFLOW); 499 } 500 } 501 502 private static ConstValue[] unknownValue = { 503 new ConstValue(1), new ConstValue(2) 504 }; 505 506 private static ConstantInfo unknownConstInfo = new ConstantInfo(); 507 508 public ConstantAnalyzer() { 509 } 510 511 public void mergeInfo(Instruction instr, 512 StackLocalInfo info) { 513 if (instr.getTmpInfo() == null) { 514 instr.setTmpInfo(info); 515 info.instr = instr; 516 info.enqueue(); 517 } else 518 ((StackLocalInfo)instr.getTmpInfo()).merge(info); 519 } 520 521 public void handleReference(Reference ref, boolean isVirtual) { 522 Main.getClassBundle().reachableReference(ref, isVirtual); 523 } 524 525 public void handleClass(String clName) { 526 int i = 0; 527 while (i < clName.length() && clName.charAt(i) == '[') 528 i++; 529 if (i < clName.length() && clName.charAt(i) == 'L') { 530 clName = clName.substring(i+1, clName.length()-1); 531 Main.getClassBundle().reachableClass(clName); 532 } 533 } 534 535 public void handleOpcode(StackLocalInfo info, Identifier fieldListener) { 536 Instruction instr = info.instr; 537 info.constInfo = unknownConstInfo; 538 539 int opcode = instr.getOpcode(); 540 Handler[] handlers = bytecode.getExceptionHandlers(); 541 for (int i=0; i< handlers.length; i++) { 542 if (handlers[i].start.getAddr() <= instr.getAddr() 543 && handlers[i].end.getAddr() >= instr.getAddr()) 544 mergeInfo(handlers[i].catcher, 545 info.poppush(info.stack.length, unknownValue[0])); 546 } 547 ConstValue result; 548 switch (opcode) { 549 case opc_nop: 550 mergeInfo(instr.getNextByAddr(), info.pop(0)); 551 break; 552 553 case opc_ldc: 554 case opc_ldc2_w: 555 result = new ConstValue(instr.getConstant()); 556 mergeInfo(instr.getNextByAddr(), info.poppush(0, result)); 557 break; 558 559 case opc_iload: case opc_lload: 560 case opc_fload: case opc_dload: case opc_aload: 561 result = info.getLocal(instr.getLocalSlot()); 562 if (result == null) { 563 dumpStackLocalInfo(); 564 System.err.println(info); 565 System.err.println(instr); 566 } 567 if (result.value != ConstValue.VOLATILE) { 568 info.constInfo = new ConstantInfo(CONSTANT, result.value); 569 result.addConstantListener(info.constInfo); 570 } 571 mergeInfo(instr.getNextByAddr(), 572 info.poppush(0, result) 573 .setLocal(instr.getLocalSlot(), result.copy())); 574 break; 575 case opc_iaload: case opc_laload: 576 case opc_faload: case opc_daload: case opc_aaload: 577 case opc_baload: case opc_caload: case opc_saload: { 578 result = unknownValue[(opcode == opc_laload 613 || opcode == opc_daload) ? 1 : 0]; 614 mergeInfo(instr.getNextByAddr(), info.poppush(2, result)); 616 break; 617 } 618 case opc_istore: case opc_fstore: case opc_astore: { 619 result = info.getStack(1); 620 if (result.value instanceof JSRTargetInfo) 621 info.constInfo.flags |= RETASTORE; 622 mergeInfo(instr.getNextByAddr(), 623 info.pop(1).setLocal(instr.getLocalSlot(), result)); 624 break; 625 } 626 case opc_lstore: case opc_dstore: { 627 mergeInfo(instr.getNextByAddr(), 628 info.pop(2).setLocal(instr.getLocalSlot(), info.getStack(2))); 629 break; 630 } 631 case opc_iastore: case opc_lastore: 632 case opc_fastore: case opc_dastore: case opc_aastore: 633 case opc_bastore: case opc_castore: case opc_sastore: { 634 int size = (opcode == opc_lastore 635 || opcode == opc_dastore) ? 2 : 1; 636 mergeInfo(instr.getNextByAddr(), info.pop(2+size)); 637 break; 638 } 639 case opc_pop: 640 mergeInfo(instr.getNextByAddr(), info.pop(1)); 641 break; 642 case opc_pop2: 643 mergeInfo(instr.getNextByAddr(), info.pop(2)); 644 break; 645 646 case opc_dup: case opc_dup_x1: case opc_dup_x2: 647 case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: 648 mergeInfo(instr.getNextByAddr(), 649 info.dup((opcode - (opc_dup - 3)) / 3, 650 (opcode - (opc_dup - 3)) % 3)); 651 break; 652 case opc_swap: 653 mergeInfo(instr.getNextByAddr(), info.swap()); 654 break; 655 656 case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd: 657 case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub: 658 case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul: 659 case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv: 660 case opc_irem: case opc_lrem: case opc_frem: case opc_drem: 661 case opc_iand: case opc_land: 662 case opc_ior : case opc_lor : 663 case opc_ixor: case opc_lxor: { 664 int size = 1 + (opcode - opc_iadd & 1); 665 ConstValue value1 = info.getStack(2*size); 666 ConstValue value2 = info.getStack(1*size); 667 boolean known = value1.value != ConstValue.VOLATILE 668 && value2.value != ConstValue.VOLATILE; 669 if (known) { 670 if (((opcode == opc_idiv || opcode == opc_irem) 671 && ((Integer )value2.value).intValue() == 0) 672 || ((opcode == opc_ldiv || opcode == opc_lrem) 673 && ((Long )value2.value).longValue() == 0)) 674 known = false; 675 } 676 if (known) { 677 Object newValue; 678 switch (opcode) { 679 case opc_iadd: 680 newValue = new Integer 681 (((Integer )value1.value).intValue() 682 + ((Integer )value2.value).intValue()); 683 break; 684 case opc_isub: 685 newValue = new Integer 686 (((Integer )value1.value).intValue() 687 - ((Integer )value2.value).intValue()); 688 break; 689 case opc_imul: 690 newValue = new Integer 691 (((Integer )value1.value).intValue() 692 * ((Integer )value2.value).intValue()); 693 break; 694 case opc_idiv: 695 newValue = new Integer 696 (((Integer )value1.value).intValue() 697 / ((Integer )value2.value).intValue()); 698 break; 699 case opc_irem: 700 newValue = new Integer 701 (((Integer )value1.value).intValue() 702 % ((Integer )value2.value).intValue()); 703 break; 704 case opc_iand: 705 newValue = new Integer 706 (((Integer )value1.value).intValue() 707 & ((Integer )value2.value).intValue()); 708 break; 709 case opc_ior: 710 newValue = new Integer 711 (((Integer )value1.value).intValue() 712 | ((Integer )value2.value).intValue()); 713 break; 714 case opc_ixor: 715 newValue = new Integer 716 (((Integer )value1.value).intValue() 717 ^ ((Integer )value2.value).intValue()); 718 break; 719 720 case opc_ladd: 721 newValue = new Long 722 (((Long )value1.value).longValue() 723 + ((Long )value2.value).longValue()); 724 break; 725 case opc_lsub: 726 newValue = new Long 727 (((Long )value1.value).longValue() 728 - ((Long )value2.value).longValue()); 729 break; 730 case opc_lmul: 731 newValue = new Long 732 (((Long )value1.value).longValue() 733 * ((Long )value2.value).longValue()); 734 break; 735 case opc_ldiv: 736 newValue = new Long 737 (((Long )value1.value).longValue() 738 / ((Long )value2.value).longValue()); 739 break; 740 case opc_lrem: 741 newValue = new Long 742 (((Long )value1.value).longValue() 743 % ((Long )value2.value).longValue()); 744 break; 745 case opc_land: 746 newValue = new Long 747 (((Long )value1.value).longValue() 748 & ((Long )value2.value).longValue()); 749 break; 750 case opc_lor: 751 newValue = new Long 752 (((Long )value1.value).longValue() 753 | ((Long )value2.value).longValue()); 754 break; 755 case opc_lxor: 756 newValue = new Long 757 (((Long )value1.value).longValue() 758 ^ ((Long )value2.value).longValue()); 759 break; 760 761 case opc_fadd: 762 newValue = new Float 763 (((Float )value1.value).floatValue() 764 + ((Float )value2.value).floatValue()); 765 break; 766 case opc_fsub: 767 newValue = new Float 768 (((Float )value1.value).floatValue() 769 - ((Float )value2.value).floatValue()); 770 break; 771 case opc_fmul: 772 newValue = new Float 773 (((Float )value1.value).floatValue() 774 * ((Float )value2.value).floatValue()); 775 break; 776 case opc_fdiv: 777 newValue = new Float 778 (((Float )value1.value).floatValue() 779 / ((Float )value2.value).floatValue()); 780 break; 781 case opc_frem: 782 newValue = new Float 783 (((Float )value1.value).floatValue() 784 % ((Float )value2.value).floatValue()); 785 break; 786 787 case opc_dadd: 788 newValue = new Double 789 (((Double )value1.value).doubleValue() 790 + ((Double )value2.value).doubleValue()); 791 break; 792 case opc_dsub: 793 newValue = new Double 794 (((Double )value1.value).doubleValue() 795 - ((Double )value2.value).doubleValue()); 796 break; 797 case opc_dmul: 798 newValue = new Double 799 (((Double )value1.value).doubleValue() 800 * ((Double )value2.value).doubleValue()); 801 break; 802 case opc_ddiv: 803 newValue = new Double 804 (((Double )value1.value).doubleValue() 805 / ((Double )value2.value).doubleValue()); 806 break; 807 case opc_drem: 808 newValue = new Double 809 (((Double )value1.value).doubleValue() 810 % ((Double )value2.value).doubleValue()); 811 break; 812 default: 813 throw new jode.AssertError("Can't happen."); 814 } 815 info.constInfo = new ConstantInfo(CONSTANT, newValue); 816 result = new ConstValue(newValue); 817 result.addConstantListener(info.constInfo); 818 value1.addConstantListener(result); 819 value2.addConstantListener(result); 820 } else 821 result = unknownValue[size-1]; 822 mergeInfo(instr.getNextByAddr(), info.poppush(2*size, result)); 823 break; 824 } 825 case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg: { 826 int size = 1 + (opcode - opc_ineg & 1); 827 ConstValue value = info.getStack(size); 828 if (value.value != ConstValue.VOLATILE) { 829 Object newValue; 830 switch (opcode) { 831 case opc_ineg: 832 newValue = new Integer 833 (-((Integer )value.value).intValue()); 834 break; 835 case opc_lneg: 836 newValue = new Long 837 (- ((Long )value.value).longValue()); 838 break; 839 case opc_fneg: 840 newValue = new Float 841 (- ((Float )value.value).floatValue()); 842 break; 843 case opc_dneg: 844 newValue = new Double 845 (- ((Double )value.value).doubleValue()); 846 break; 847 default: 848 throw new jode.AssertError("Can't happen."); 849 } 850 info.constInfo = new ConstantInfo(CONSTANT, newValue); 851 result = new ConstValue(newValue); 852 result.addConstantListener(info.constInfo); 853 value.addConstantListener(result); 854 } else 855 result = unknownValue[size-1]; 856 mergeInfo(instr.getNextByAddr(), info.poppush(size, result)); 857 break; 858 } 859 case opc_ishl: case opc_lshl: 860 case opc_ishr: case opc_lshr: 861 case opc_iushr: case opc_lushr: { 862 int size = 1 + (opcode - opc_iadd & 1); 863 ConstValue value1 = info.getStack(size+1); 864 ConstValue value2 = info.getStack(1); 865 if (value1.value != ConstValue.VOLATILE 866 && value2.value != ConstValue.VOLATILE) { 867 Object newValue; 868 switch (opcode) { 869 case opc_ishl: 870 newValue = new Integer 871 (((Integer )value1.value).intValue() 872 << ((Integer )value2.value).intValue()); 873 break; 874 case opc_ishr: 875 newValue = new Integer 876 (((Integer )value1.value).intValue() 877 >> ((Integer )value2.value).intValue()); 878 break; 879 case opc_iushr: 880 newValue = new Integer 881 (((Integer )value1.value).intValue() 882 >>> ((Integer )value2.value).intValue()); 883 break; 884 885 case opc_lshl: 886 newValue = new Long 887 (((Long )value1.value).longValue() 888 << ((Integer )value2.value).intValue()); 889 break; 890 case opc_lshr: 891 newValue = new Long 892 (((Long )value1.value).longValue() 893 >> ((Integer )value2.value).intValue()); 894 break; 895 case opc_lushr: 896 newValue = new Long 897 (((Long )value1.value).longValue() 898 >>> ((Integer )value2.value).intValue()); 899 break; 900 default: 901 throw new jode.AssertError("Can't happen."); 902 } 903 info.constInfo = new ConstantInfo(CONSTANT, newValue); 904 result = new ConstValue(newValue); 905 result.addConstantListener(info.constInfo); 906 value1.addConstantListener(result); 907 value2.addConstantListener(result); 908 } else 909 result = unknownValue[size-1]; 910 mergeInfo(instr.getNextByAddr(), info.poppush(size+1, result)); 911 break; 912 } 913 case opc_iinc: { 914 ConstValue local = info.getLocal(instr.getLocalSlot()); 915 if (local.value != ConstValue.VOLATILE) { 916 result = new ConstValue 917 (new Integer (((Integer )local.value).intValue() 918 + instr.getIncrement())); 919 local.addConstantListener(result); 920 } else 921 result = unknownValue[0]; 922 mergeInfo(instr.getNextByAddr(), 923 info.copy().setLocal(instr.getLocalSlot(), result)); 924 break; 925 } 926 case opc_i2l: case opc_i2f: case opc_i2d: 927 case opc_l2i: case opc_l2f: case opc_l2d: 928 case opc_f2i: case opc_f2l: case opc_f2d: 929 case opc_d2i: case opc_d2l: case opc_d2f: { 930 int insize = 1 + ((opcode - opc_i2l) / 3 & 1); 931 ConstValue stack = info.getStack(insize); 932 if (stack.value != ConstValue.VOLATILE) { 933 Object newVal; 934 switch(opcode) { 935 case opc_l2i: case opc_f2i: case opc_d2i: 936 newVal = new Integer (((Number )stack.value).intValue()); 937 break; 938 case opc_i2l: case opc_f2l: case opc_d2l: 939 newVal = new Long (((Number )stack.value).longValue()); 940 break; 941 case opc_i2f: case opc_l2f: case opc_d2f: 942 newVal = new Float (((Number )stack.value).floatValue()); 943 break; 944 case opc_i2d: case opc_l2d: case opc_f2d: 945 newVal = new Double (((Number )stack.value).doubleValue()); 946 break; 947 default: 948 throw new jode.AssertError("Can't happen."); 949 } 950 info.constInfo = new ConstantInfo(CONSTANT, newVal); 951 result = new ConstValue(newVal); 952 result.addConstantListener(info.constInfo); 953 stack.addConstantListener(result); 954 } else { 955 switch (opcode) { 956 case opc_i2l: case opc_f2l: case opc_d2l: 957 case opc_i2d: case opc_l2d: case opc_f2d: 958 result = unknownValue[1]; 959 break; 960 default: 961 result = unknownValue[0]; 962 } 963 } 964 mergeInfo(instr.getNextByAddr(), info.poppush(insize, result)); 965 break; 966 } 967 case opc_i2b: case opc_i2c: case opc_i2s: { 968 ConstValue stack = info.getStack(1); 969 if (stack.value != ConstValue.VOLATILE) { 970 int val = ((Integer )stack.value).intValue(); 971 switch(opcode) { 972 case opc_i2b: 973 val = (byte) val; 974 break; 975 case opc_i2c: 976 val = (char) val; 977 break; 978 case opc_i2s: 979 val = (short) val; 980 break; 981 } 982 Integer newVal = new Integer (val); 983 info.constInfo = new ConstantInfo(CONSTANT, newVal); 984 result = new ConstValue(newVal); 985 stack.addConstantListener(info.constInfo); 986 stack.addConstantListener(result); 987 } else 988 result = unknownValue[0]; 989 mergeInfo(instr.getNextByAddr(), 990 info.poppush(1, result)); 991 break; 992 } 993 case opc_lcmp: { 994 ConstValue val1 = info.getStack(4); 995 ConstValue val2 = info.getStack(2); 996 if (val1.value != ConstValue.VOLATILE 997 && val2.value != ConstValue.VOLATILE) { 998 long value1 = ((Long ) val1.value).longValue(); 999 long value2 = ((Long ) val1.value).longValue(); 1000 Integer newVal = new Integer (value1 == value2 ? 0 1001 : value1 < value2 ? -1 : 1); 1002 info.constInfo = new ConstantInfo(CONSTANT, newVal); 1003 result = new ConstValue(newVal); 1004 result.addConstantListener(info.constInfo); 1005 val1.addConstantListener(result); 1006 val2.addConstantListener(result); 1007 } else 1008 result = unknownValue[0]; 1009 mergeInfo(instr.getNextByAddr(), info.poppush(4, result)); 1010 break; 1011 } 1012 case opc_fcmpl: case opc_fcmpg: { 1013 ConstValue val1 = info.getStack(2); 1014 ConstValue val2 = info.getStack(1); 1015 if (val1.value != ConstValue.VOLATILE 1016 && val2.value != ConstValue.VOLATILE) { 1017 float value1 = ((Float ) val1.value).floatValue(); 1018 float value2 = ((Float ) val1.value).floatValue(); 1019 Integer newVal = new Integer 1020 (value1 == value2 ? 0 1021 : ( opcode == opc_fcmpg 1022 ? (value1 < value2 ? -1 : 1) 1023 : (value1 > value2 ? 1 : -1))); 1024 info.constInfo = new ConstantInfo(CONSTANT, newVal); 1025 result = new ConstValue(newVal); 1026 result.addConstantListener(info.constInfo); 1027 val1.addConstantListener(result); 1028 val2.addConstantListener(result); 1029 } else 1030 result = unknownValue[0]; 1031 mergeInfo(instr.getNextByAddr(), info.poppush(2, result)); 1032 break; 1033 } 1034 case opc_dcmpl: case opc_dcmpg: { 1035 ConstValue val1 = info.getStack(4); 1036 ConstValue val2 = info.getStack(2); 1037 if (val1.value != ConstValue.VOLATILE 1038 && val2.value != ConstValue.VOLATILE) { 1039 double value1 = ((Double ) val1.value).doubleValue(); 1040 double value2 = ((Double ) val1.value).doubleValue(); 1041 Integer newVal = new Integer 1042 (value1 == value2 ? 0 1043 : ( opcode == opc_dcmpg 1044 ? (value1 < value2 ? -1 : 1) 1045 : (value1 > value2 ? 1 : -1))); 1046 info.constInfo = new ConstantInfo(CONSTANT, newVal); 1047 result = new ConstValue(newVal); 1048 result.addConstantListener(info.constInfo); 1049 val1.addConstantListener(result); 1050 val2.addConstantListener(result); 1051 } else 1052 result = unknownValue[0]; 1053 mergeInfo(instr.getNextByAddr(), info.poppush(4, result)); 1054 break; 1055 } 1056 case opc_ifeq: case opc_ifne: 1057 case opc_iflt: case opc_ifge: 1058 case opc_ifgt: case opc_ifle: 1059 case opc_if_icmpeq: case opc_if_icmpne: 1060 case opc_if_icmplt: case opc_if_icmpge: 1061 case opc_if_icmpgt: case opc_if_icmple: 1062 case opc_if_acmpeq: case opc_if_acmpne: 1063 case opc_ifnull: case opc_ifnonnull: { 1064 int size = 1; 1065 ConstValue stacktop = info.getStack(1); 1066 ConstValue other = null; 1067 boolean known = stacktop.value != ConstValue.VOLATILE; 1068 if (opcode >= opc_if_icmpeq && opcode <= opc_if_acmpne) { 1069 other = info.getStack(2); 1070 size = 2; 1071 known &= other.value != ConstValue.VOLATILE; 1072 } 1073 if (known) { 1074 stacktop.addConstantListener(info); 1075 if (other != null) 1076 other.addConstantListener(info); 1077 1078 Instruction pc = instr.getNextByAddr(); 1079 int opc_mask; 1080 if (opcode >= opc_if_acmpeq) { 1081 if (opcode >= opc_ifnull) { 1082 opc_mask = stacktop.value == null 1083 ? CMP_EQUAL_MASK : CMP_GREATER_MASK; 1084 opcode -= opc_ifnull; 1085 } else { 1086 opc_mask = stacktop.value == other.value 1087 ? CMP_EQUAL_MASK : CMP_GREATER_MASK; 1088 opcode -= opc_if_acmpeq; 1089 } 1090 } else { 1091 int value = ((Integer ) stacktop.value).intValue(); 1092 if (opcode >= opc_if_icmpeq) { 1093 int val1 = ((Integer ) other.value).intValue(); 1094 opc_mask = (val1 == value ? CMP_EQUAL_MASK 1095 : val1 < value ? CMP_LESS_MASK 1096 : CMP_GREATER_MASK); 1097 opcode -= opc_if_icmpeq; 1098 } else { 1099 opc_mask = (value == 0 ? CMP_EQUAL_MASK 1100 : value < 0 ? CMP_LESS_MASK 1101 : CMP_GREATER_MASK); 1102 opcode -= opc_ifeq; 1103 } 1104 } 1105 1106 if ((opc_mask & (1<<opcode)) != 0) 1107 pc = instr.getSingleSucc(); 1108 1109 info.constInfo = new ConstantInfo(CONSTANTFLOW, pc); 1110 mergeInfo(pc, info.pop(size)); 1111 } else { 1112 mergeInfo(instr.getNextByAddr(), info.pop(size)); 1113 mergeInfo(instr.getSingleSucc(), info.pop(size)); 1114 } 1115 break; 1116 } 1117 case opc_goto: 1118 mergeInfo(instr.getSingleSucc(), info.copy()); 1119 break; 1120 case opc_lookupswitch: { 1121 ConstValue stacktop = info.getStack(1); 1122 if (stacktop.value != ConstValue.VOLATILE) { 1123 stacktop.addConstantListener(info); 1124 Instruction pc; 1125 int value = ((Integer ) stacktop.value).intValue(); 1126 int[] values = instr.getValues(); 1127 pc = instr.getSuccs()[values.length]; 1128 for (int i=0; i< values.length; i++) { 1129 if (values[i] == value) { 1130 pc = instr.getSuccs()[i]; 1131 break; 1132 } 1133 } 1134 info.constInfo = new ConstantInfo(CONSTANTFLOW, pc); 1135 mergeInfo(pc, info.pop(1)); 1136 } else { 1137 for (int i=0; i < instr.getSuccs().length; i++) 1138 mergeInfo(instr.getSuccs()[i], info.pop(1)); 1139 } 1140 break; 1141 } 1142 case opc_jsr: 1143 if (instr.getSingleSucc().getOpcode() != opc_astore) 1146 throw new RuntimeException ("Can't handle jsr to non astores"); 1147 StackLocalInfo oldJsrInfo = 1148 (StackLocalInfo) instr.getSingleSucc().getTmpInfo(); 1149 if (oldJsrInfo != null) { 1150 result = oldJsrInfo.getStack(1); 1151 if (oldJsrInfo.retInfo != null 1152 && result.value instanceof JSRTargetInfo) { 1153 mergeInfo(instr.getNextByAddr(), 1154 info.copy() 1155 .mergeRetLocals((JSRTargetInfo) result.value, 1156 oldJsrInfo.retInfo)); 1157 } 1158 } else { 1159 result = new ConstValue 1160 (new JSRTargetInfo(instr.getSingleSucc())); 1161 } 1162 mergeInfo(instr.getSingleSucc(), info.poppush(0, result)); 1163 break; 1164 case opc_ret: { 1165 result = info.getLocal(instr.getLocalSlot()); 1168 JSRTargetInfo jsrInfo = (JSRTargetInfo) result.value; 1169 jsrInfo.setRetInfo(info); 1170 result.addConstantListener(info); 1171 Instruction jsrTarget = jsrInfo.jsrTarget; 1172 StackLocalInfo jsrTargetStackInfo = 1173 (StackLocalInfo) jsrTarget.getTmpInfo(); 1174 jsrTargetStackInfo.retInfo = info; 1175 jsrTargetStackInfo.constInfo.flags |= RETURNINGJSR; 1176 Instruction[] jsrs = jsrTarget.getPreds(); 1177 for (int i=0; i < jsrs.length; i++) { 1178 Instruction jsr = jsrs[i]; 1179 if (jsr.getTmpInfo() != null) { 1180 mergeInfo(jsr.getNextByAddr(), 1181 ((StackLocalInfo) jsr.getTmpInfo()).copy() 1182 .mergeRetLocals(jsrInfo, info)); 1183 } 1184 } 1185 break; 1186 } 1187 case opc_ireturn: case opc_lreturn: 1188 case opc_freturn: case opc_dreturn: case opc_areturn: 1189 case opc_return: 1190 case opc_athrow: 1191 break; 1192 1193 case opc_putstatic: 1194 case opc_putfield: { 1195 FieldIdentifier fi = (FieldIdentifier) canonizeReference(instr); 1196 Reference ref = instr.getReference(); 1197 int size = TypeSignature.getTypeSize(ref.getType()); 1198 if (fi != null && !fi.isNotConstant()) { 1199 ConstValue stacktop = info.getStack(size); 1200 Object fieldVal = fi.getConstant(); 1201 if (fieldVal == null) 1202 fieldVal = runtime.getDefaultValue(ref.getType()); 1203 if (stacktop.value == null ? fieldVal == null 1204 : stacktop.value.equals(fieldVal)) { 1205 stacktop.addConstantListener(info); 1206 } else { 1207 fi.setNotConstant(); 1208 fieldNotConstant(fi); 1209 } 1210 } 1211 size += (opcode == opc_putstatic) ? 0 : 1; 1212 mergeInfo(instr.getNextByAddr(), info.pop(size)); 1213 break; 1214 } 1215 case opc_getstatic: 1216 case opc_getfield: { 1217 int size = (opcode == opc_getstatic) ? 0 : 1; 1218 FieldIdentifier fi = (FieldIdentifier) canonizeReference(instr); 1219 Reference ref = instr.getReference(); 1220 int typesize = TypeSignature.getTypeSize(ref.getType()); 1221 if (fi != null) { 1222 if (fi.isNotConstant()) { 1223 fi.setReachable(); 1224 result = unknownValue[typesize - 1]; 1225 } else { 1226 Object obj = fi.getConstant(); 1227 if (obj == null) 1228 obj = runtime.getDefaultValue(ref.getType()); 1229 info.constInfo = new ConstantInfo(CONSTANT, obj); 1230 result = new ConstValue(obj); 1231 result.addConstantListener(info.constInfo); 1232 fi.addFieldListener(fieldListener); 1233 } 1234 } else 1235 result = unknownValue[typesize - 1]; 1236 mergeInfo(instr.getNextByAddr(), info.poppush(size, result)); 1237 break; 1238 } 1239 case opc_invokespecial: 1240 case opc_invokestatic: 1241 case opc_invokeinterface: 1242 case opc_invokevirtual: { 1243 canonizeReference(instr); 1244 Reference ref = instr.getReference(); 1245 boolean constant = true; 1246 int size = 0; 1247 Object cls = null; 1248 String [] paramTypes 1249 = TypeSignature.getParameterTypes(ref.getType()); 1250 Object [] args = new Object [paramTypes.length]; 1251 ConstValue clsValue = null; 1252 ConstValue[] argValues = new ConstValue[paramTypes.length]; 1253 1254 for (int i = paramTypes.length - 1; i >= 0; i--) { 1255 size += TypeSignature.getTypeSize(paramTypes[i]); 1256 Object value = (argValues[i] = info.getStack(size)).value; 1257 if (value != ConstValue.VOLATILE) 1258 args[i] = value; 1259 else 1260 constant = false; 1261 } 1262 1263 if (opcode != opc_invokestatic) { 1264 size++; 1265 clsValue = info.getStack(size); 1266 cls = clsValue.value; 1267 if (cls == ConstValue.VOLATILE || cls == null) 1268 constant = false; 1269 } 1270 String retType = TypeSignature.getReturnType(ref.getType()); 1271 if (retType.equals("V")) { 1272 handleReference(ref, opcode == opc_invokevirtual 1273 || opcode == opc_invokeinterface); 1274 mergeInfo(instr.getNextByAddr(), info.pop(size)); 1275 break; 1276 } 1277 if (constant && !runtime.isWhite(retType)) { 1278 1279 constant = false; 1280 } 1281 Object methodResult = null; 1282 if (constant) { 1283 try { 1284 methodResult = runtime.invokeMethod 1285 (ref, opcode != opc_invokespecial, cls, args); 1286 } catch (InterpreterException ex) { 1287 constant = false; 1288 if (jode.GlobalOptions.verboseLevel > 3) 1289 GlobalOptions.err.println("Can't interpret "+ref+": " 1290 + ex.getMessage()); 1291 1292 } catch (InvocationTargetException ex) { 1293 constant = false; 1294 if (jode.GlobalOptions.verboseLevel > 3) 1295 GlobalOptions.err.println("Method "+ref 1296 +" throwed exception: " 1297 + ex.getTargetException()); 1298 1299 } 1300 } 1301 ConstValue returnVal; 1302 if (!constant) { 1303 handleReference(ref, opcode == opc_invokevirtual 1304 || opcode == opc_invokeinterface); 1305 int retsize = TypeSignature.getTypeSize(retType); 1306 returnVal = unknownValue[retsize - 1]; 1307 } else { 1308 info.constInfo = new ConstantInfo(CONSTANT, methodResult); 1309 returnVal = new ConstValue(methodResult); 1310 returnVal.addConstantListener(info.constInfo); 1311 if (clsValue != null) 1312 clsValue.addConstantListener(returnVal); 1313 for (int i=0; i< argValues.length; i++) 1314 argValues[i].addConstantListener(returnVal); 1315 } 1316 mergeInfo(instr.getNextByAddr(), info.poppush(size, returnVal)); 1317 break; 1318 } 1319 1320 case opc_new: { 1321 handleClass(instr.getClazzType()); 1322 mergeInfo(instr.getNextByAddr(), info.poppush(0, unknownValue[0])); 1323 break; 1324 } 1325 case opc_arraylength: { 1326 result = unknownValue[0]; 1336 mergeInfo(instr.getNextByAddr(), info.poppush(1, result)); 1337 break; 1338 } 1339 case opc_checkcast: { 1340 handleClass(instr.getClazzType()); 1341 mergeInfo(instr.getNextByAddr(), info.pop(0)); 1342 break; 1343 } 1344 case opc_instanceof: { 1345 handleClass(instr.getClazzType()); 1346 mergeInfo(instr.getNextByAddr(), info.poppush(1, unknownValue[0])); 1347 break; 1348 } 1349 case opc_monitorenter: 1350 case opc_monitorexit: 1351 mergeInfo(instr.getNextByAddr(), info.pop(1)); 1352 break; 1353 case opc_multianewarray: 1354 handleClass(instr.getClazzType()); 1355 mergeInfo(instr.getNextByAddr(), 1356 info.poppush(instr.getDimensions(), unknownValue[0])); 1357 break; 1358 default: 1359 throw new IllegalArgumentException ("Invalid opcode "+opcode); 1360 } 1361 } 1362 1363 public void fieldNotConstant(FieldIdentifier fi) { 1364 for (Iterator iter = bytecode.getInstructions().iterator(); 1365 iter.hasNext(); ) { 1366 Instruction instr = (Instruction) iter.next(); 1367 if (instr.getOpcode() == opc_getfield 1368 || instr.getOpcode() == opc_getstatic) { 1369 Reference ref = instr.getReference(); 1370 if (ref.getName().equals(fi.getName()) 1371 && ref.getType().equals(fi.getType()) 1372 && instr.getTmpInfo() != null) { 1373 ((StackLocalInfo) instr.getTmpInfo()).enqueue(); 1374 } 1375 } 1376 } 1377 } 1378 1379 public void dumpStackLocalInfo() { 1380 for (Iterator iter = bytecode.getInstructions().iterator(); 1381 iter.hasNext(); ) { 1382 Instruction instr = (Instruction) iter.next(); 1383 System.err.println(""+instr.getTmpInfo()); 1384 System.err.println(instr.getDescription()); 1385 } 1386 } 1387 1388 public void analyzeCode(MethodIdentifier methodIdent, 1389 BytecodeInfo bytecode) { 1390 this.bytecode = bytecode; 1391 TodoQueue modifiedQueue = new TodoQueue(); 1392 MethodInfo minfo = bytecode.getMethodInfo(); 1393 1394 for (Iterator iter = bytecode.getInstructions().iterator(); 1395 iter.hasNext(); ) { 1396 Instruction instr = (Instruction) iter.next(); 1397 instr.setTmpInfo(null); 1398 } 1399 1400 StackLocalInfo firstInfo = new StackLocalInfo 1401 (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(), 1402 modifiedQueue); 1403 firstInfo.instr = (Instruction) bytecode.getInstructions().get(0); 1404 firstInfo.instr.setTmpInfo(firstInfo); 1405 firstInfo.enqueue(); 1406 runtime.setFieldListener(methodIdent); 1407 while (modifiedQueue.first != null) { 1408 StackLocalInfo info = modifiedQueue.first; 1409 modifiedQueue.first = info.nextOnQueue; 1410 info.nextOnQueue = null; 1411 handleOpcode(info, methodIdent); 1412 } 1413 runtime.setFieldListener(null); 1414 1415 Handler[] handlers = bytecode.getExceptionHandlers(); 1416 for (int i=0; i< handlers.length; i++) { 1417 if (handlers[i].catcher.getTmpInfo() != null 1418 && handlers[i].type != null) 1419 Main.getClassBundle().reachableClass(handlers[i].type); 1420 } 1421 for (Iterator iter = bytecode.getInstructions().iterator(); 1422 iter.hasNext(); ) { 1423 Instruction instr = (Instruction) iter.next(); 1424 StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo(); 1425 if (info != null) { 1426 if (info.constInfo.flags == 0) 1427 instr.setTmpInfo(unknownConstInfo); 1428 else 1429 instr.setTmpInfo(info.constInfo); 1430 } 1431 } 1432 } 1433 1434 public static void replaceWith(ListIterator iter, Instruction instr, 1435 Instruction replacement) { 1436 switch(instr.getOpcode()) { 1437 case opc_goto: 1438 case opc_ldc: 1439 case opc_ldc2_w: 1440 case opc_iload: case opc_lload: 1441 case opc_fload: case opc_dload: case opc_aload: 1442 case opc_getstatic: 1443 if (replacement == null) 1444 iter.remove(); 1445 else 1446 iter.set(replacement); 1447 return; 1448 case opc_ifeq: case opc_ifne: 1449 case opc_iflt: case opc_ifge: 1450 case opc_ifgt: case opc_ifle: 1451 case opc_ifnull: case opc_ifnonnull: 1452 case opc_arraylength: 1453 case opc_getfield: 1454 case opc_i2l: case opc_i2f: case opc_i2d: 1455 case opc_f2i: case opc_f2l: case opc_f2d: 1456 case opc_i2b: case opc_i2c: case opc_i2s: 1457 case opc_ineg: case opc_fneg: 1458 iter.set(new Instruction(opc_pop)); 1459 break; 1460 case opc_lcmp: 1461 case opc_dcmpg: case opc_dcmpl: 1462 case opc_ladd: case opc_dadd: 1463 case opc_lsub: case opc_dsub: 1464 case opc_lmul: case opc_dmul: 1465 case opc_ldiv: case opc_ddiv: 1466 case opc_lrem: case opc_drem: 1467 case opc_land: case opc_lor : case opc_lxor: 1468 iter.set(new Instruction(opc_pop2)); 1469 iter.add(new Instruction(opc_pop2)); 1470 break; 1471 case opc_if_icmpeq: case opc_if_icmpne: 1472 case opc_if_icmplt: case opc_if_icmpge: 1473 case opc_if_icmpgt: case opc_if_icmple: 1474 case opc_if_acmpeq: case opc_if_acmpne: 1475 case opc_fcmpg: case opc_fcmpl: 1476 case opc_l2i: case opc_l2f: case opc_l2d: 1477 case opc_d2i: case opc_d2l: case opc_d2f: 1478 case opc_lneg: case opc_dneg: 1479 case opc_iadd: case opc_fadd: 1480 case opc_isub: case opc_fsub: 1481 case opc_imul: case opc_fmul: 1482 case opc_idiv: case opc_fdiv: 1483 case opc_irem: case opc_frem: 1484 case opc_iand: case opc_ior : case opc_ixor: 1485 case opc_ishl: case opc_ishr: case opc_iushr: 1486 case opc_iaload: case opc_laload: 1487 case opc_faload: case opc_daload: case opc_aaload: 1488 case opc_baload: case opc_caload: case opc_saload: 1489 iter.set(new Instruction(opc_pop2)); 1490 break; 1491 1492 case opc_lshl: case opc_lshr: case opc_lushr: 1493 iter.set(new Instruction(opc_pop)); 1494 iter.add(new Instruction(opc_pop2)); 1495 break; 1496 case opc_putstatic: 1497 case opc_putfield: 1498 if (TypeSignature 1499 .getTypeSize(instr.getReference().getType()) == 2) { 1500 iter.set(new Instruction(opc_pop2)); 1501 if (instr.getOpcode() == opc_putfield) 1502 iter.add(new Instruction(opc_pop)); 1503 } else 1504 iter.set(new Instruction(instr.getOpcode() == opc_putfield 1505 ? opc_pop2 : opc_pop)); 1506 break; 1507 case opc_invokespecial: 1508 case opc_invokestatic: 1509 case opc_invokeinterface: 1510 case opc_invokevirtual: { 1511 Reference ref = instr.getReference(); 1512 String [] pt = TypeSignature.getParameterTypes(ref.getType()); 1513 int len = pt.length; 1514 1515 if (len > 0) { 1516 iter.set(new Instruction(TypeSignature.getTypeSize(pt[--len]) 1517 + opc_pop - 1)); 1518 for (int i = len - 1; i >= 0; i--) 1519 iter.add(new Instruction(TypeSignature.getTypeSize(pt[i]) 1520 + opc_pop - 1)); 1521 if (instr.getOpcode() != opc_invokestatic) 1522 iter.add(new Instruction(opc_pop)); 1523 } else if (instr.getOpcode() != opc_invokestatic) { 1524 iter.set(new Instruction(opc_pop)); 1525 } else { 1526 if (replacement == null) 1527 iter.remove(); 1528 else 1529 iter.set(replacement); 1530 return; 1531 } 1532 1533 } 1534 } 1535 if (replacement != null) 1536 iter.add(replacement); 1537 } 1538 1539 public void appendJump(ListIterator iter, Instruction dest) { 1540 1541 Instruction gotoInstr = new Instruction(Instruction.opc_goto); 1542 gotoInstr.setSuccs(dest); 1543 iter.add(gotoInstr); 1544 } 1545 1546 public void transformCode(BytecodeInfo bytecode) { 1547 for (ListIterator iter = bytecode.getInstructions().listIterator(); 1548 iter.hasNext(); ) { 1549 Instruction instr = (Instruction) iter.next(); 1550 ConstantInfo info = (ConstantInfo) instr.getTmpInfo(); 1551 instr.setTmpInfo(null); 1552 1553 if (info == null 1554 || (info.flags & (RETURNINGJSR | RETASTORE)) == RETASTORE) { 1555 1557 iter.remove(); 1558 } else if ((info.flags & CONSTANT) != 0) { 1559 if (instr.getOpcode() > opc_ldc2_w) { 1560 Instruction ldcInstr 1561 = new Instruction(info.constant instanceof Long 1562 || info.constant instanceof Double 1563 ? opc_ldc2_w : opc_ldc); 1564 ldcInstr.setConstant(info.constant); 1565 replaceWith(iter, instr, ldcInstr); 1566 if (GlobalOptions.verboseLevel > 2) 1567 GlobalOptions.err.println 1568 (bytecode + ": Replacing " + instr 1569 + " with constant " + info.constant); 1570 } 1571 } else if ((info.flags & CONSTANTFLOW) != 0) { 1572 Instruction pc = (Instruction) info.constant; 1573 if (instr.getOpcode() >= opc_if_icmpeq 1574 && instr.getOpcode() <= opc_if_acmpne) 1575 iter.set(new Instruction(opc_pop2)); 1576 else 1577 iter.set(new Instruction(opc_pop)); 1578 if (GlobalOptions.verboseLevel > 2) 1579 GlobalOptions.err.println 1580 (bytecode + ": Replacing " + instr 1581 + " with goto " + pc.getAddr()); 1582 while (iter.hasNext()) { 1583 ConstantInfo nextinfo = (ConstantInfo) 1584 ((Instruction) iter.next()).getTmpInfo(); 1585 if (nextinfo != null) { 1586 Instruction nextInstr = (Instruction) iter.previous(); 1587 if (pc != nextInstr) 1588 appendJump(iter, pc); 1589 break; 1590 } 1591 1592 iter.remove(); 1593 } 1594 1595 } else { 1596 int opcode = instr.getOpcode(); 1597 switch (opcode) { 1598 case opc_nop: 1599 iter.remove(); 1600 break; 1601 1602 case opc_jsr: 1603 ConstantInfo jsrinfo = (ConstantInfo) 1604 instr.getSingleSucc().getTmpInfo(); 1605 if ((jsrinfo.flags & RETURNINGJSR) != 0) 1606 1607 break; 1608 1609 1613 Instruction gotoInstr = new Instruction(opc_goto); 1614 gotoInstr.setSuccs(instr.getSingleSucc()); 1615 iter.set(gotoInstr); 1616 1617 case opc_goto: 1618 case opc_ifeq: case opc_ifne: 1619 case opc_iflt: case opc_ifge: 1620 case opc_ifgt: case opc_ifle: 1621 case opc_ifnull: case opc_ifnonnull: 1622 case opc_if_icmpeq: case opc_if_icmpne: 1623 case opc_if_icmplt: case opc_if_icmpge: 1624 case opc_if_icmpgt: case opc_if_icmple: 1625 case opc_if_acmpeq: case opc_if_acmpne: 1626 1627 while (iter.hasNext()) { 1628 ConstantInfo nextinfo = (ConstantInfo) 1629 ((Instruction) iter.next()).getTmpInfo(); 1630 if (nextinfo != null 1631 && ((nextinfo.flags & (RETURNINGJSR | RETASTORE)) 1632 != RETASTORE)) { 1633 1634 Instruction nextInstr 1635 = (Instruction) iter.previous(); 1636 if (instr.getSingleSucc() == nextInstr) { 1637 1638 iter.previous(); 1639 iter.next(); 1640 replaceWith(iter, instr, null); 1641 } 1642 break; 1643 } 1644 1645 iter.remove(); 1646 } 1647 break; 1648 1649 case opc_putstatic: 1650 case opc_putfield: { 1651 Reference ref = instr.getReference(); 1652 FieldIdentifier fi = (FieldIdentifier) 1653 Main.getClassBundle().getIdentifier(ref); 1654 if (fi != null 1655 && (Main.stripping & Main.STRIP_UNREACH) != 0 1656 && !fi.isReachable()) { 1657 replaceWith(iter, instr, null); 1658 } 1659 break; 1660 } 1661 } 1662 } 1663 } 1664 } 1665} 1666 | Popular Tags |