This commit was manufactured by cvs2svn to create tag 'jode_1_0_91'.

git-svn-id: https://svn.code.sf.net/p/jode/code/tags/jode_1_0_91@1156 379699f6-c40d-0410-875b-85095c16579e
jode_1_0_91
(no author) 25 years ago
parent ff298fb733
commit 65ce4f3b53
  1. 1
      CVSROOT/cvsignore
  2. 2
      jode/jode/jvm/.cvsignore
  3. 1127
      jode/jode/jvm/CodeVerifier.java.in
  4. 1901
      jode/jode/jvm/Interpreter.j
  5. 754
      jode/jode/jvm/Interpreter.java.in
  6. 35
      jode/jode/jvm/InterpreterException.java
  7. 36
      jode/jode/jvm/Makefile.am
  8. 54
      jode/jode/jvm/NewObject.java
  9. 121
      jode/jode/jvm/RuntimeEnvironment.java
  10. 231
      jode/jode/jvm/SimpleRuntimeEnvironment.java
  11. 327
      jode/jode/jvm/SyntheticAnalyzer.java.in
  12. 98
      jode/jode/jvm/Value.java
  13. 36
      jode/jode/jvm/VerifyException.java
  14. 2
      jode/jode/obfuscator/.cvsignore
  15. 501
      jode/jode/obfuscator/ClassBundle.java.in
  16. 898
      jode/jode/obfuscator/ClassIdentifier.java.in
  17. 25
      jode/jode/obfuscator/CodeAnalyzer.java
  18. 25
      jode/jode/obfuscator/CodeTransformer.java
  19. 1706
      jode/jode/obfuscator/ConstantAnalyzer.java.in
  20. 311
      jode/jode/obfuscator/ConstantRuntimeEnvironment.java.in
  21. 140
      jode/jode/obfuscator/FieldIdentifier.java.in
  22. 248
      jode/jode/obfuscator/Identifier.java.in
  23. 44
      jode/jode/obfuscator/IdentifierMatcher.java
  24. 62
      jode/jode/obfuscator/LocalIdentifier.java.in
  25. 940
      jode/jode/obfuscator/LocalOptimizer.java.in
  26. 34
      jode/jode/obfuscator/LocalizeFieldTransformer.java.in
  27. 183
      jode/jode/obfuscator/Main.java.in
  28. 55
      jode/jode/obfuscator/Makefile.am
  29. 235
      jode/jode/obfuscator/MethodIdentifier.java.in
  30. 269
      jode/jode/obfuscator/ModifierMatcher.java
  31. 109
      jode/jode/obfuscator/MultiIdentifierMatcher.java.in
  32. 98
      jode/jode/obfuscator/NameSwapper.java.in
  33. 27
      jode/jode/obfuscator/OptionHandler.java.in
  34. 454
      jode/jode/obfuscator/PackageIdentifier.java.in
  35. 26
      jode/jode/obfuscator/ParseException.java
  36. 307
      jode/jode/obfuscator/RemovePopAnalyzer.java.in
  37. 32
      jode/jode/obfuscator/Renamer.java.in
  38. 279
      jode/jode/obfuscator/ScriptParser.java.in
  39. 182
      jode/jode/obfuscator/SimpleAnalyzer.java.in
  40. 141
      jode/jode/obfuscator/StrongRenamer.java.in
  41. 76
      jode/jode/obfuscator/TranslationTable.java.in
  42. 41
      jode/jode/obfuscator/UniqueRenamer.java.in
  43. 108
      jode/jode/obfuscator/WildCard.java.in
  44. 2
      jode/jode/swingui/.cvsignore
  45. 270
      jode/jode/swingui/HierarchyTreeModel.java.in
  46. 353
      jode/jode/swingui/Main.java.in
  47. 30
      jode/jode/swingui/Makefile.am
  48. 208
      jode/jode/swingui/PackagesTreeModel.java.in
  49. 2
      jode/jode/type/.cvsignore
  50. 251
      jode/jode/type/ArrayType.java
  51. 560
      jode/jode/type/ClassInterfacesType.java
  52. 279
      jode/jode/type/IntegerType.java
  53. 35
      jode/jode/type/Makefile.am
  54. 100
      jode/jode/type/MethodType.java
  55. 85
      jode/jode/type/NullType.java
  56. 222
      jode/jode/type/RangeType.java
  57. 143
      jode/jode/type/ReferenceType.java
  58. 555
      jode/jode/type/Type.java.in
  59. 2
      jode/jode/util/.cvsignore
  60. 38
      jode/jode/util/ArrayEnum.java
  61. 31
      jode/jode/util/Makefile.am
  62. 98
      jode/jode/util/SimpleMap.java.in
  63. 90
      jode/jode/util/SimpleSet.java.in
  64. 259
      jode/jode/util/UnifyHash.java.in
  65. 2
      jode/test/.cvsignore
  66. 189
      jode/test/AnonymousClass.java
  67. 200
      jode/test/AnonymousJavac.java
  68. 28
      jode/test/ArrayCloneTest.java
  69. 92
      jode/test/ArrayTest.java
  70. 90
      jode/test/AssignOp.java
  71. 12
      jode/test/Base.j
  72. 29
      jode/test/Child.j
  73. 36
      jode/test/ClassOpTest.java
  74. 71
      jode/test/ConstantTypes.java
  75. 99
      jode/test/CountOpcodes.java
  76. 124
      jode/test/EvilTypes.j
  77. 91
      jode/test/Expressions.java
  78. 218
      jode/test/Flow.java
  79. 35
      jode/test/For.java
  80. 50
      jode/test/HintTypeTest.java
  81. 33
      jode/test/IfCombine.java
  82. 34
      jode/test/InlineTest.java
  83. 21
      jode/test/InlinedAnon.java
  84. 99
      jode/test/InnerClass.java
  85. 69
      jode/test/InnerCompat.java
  86. 33
      jode/test/JavacBug.java
  87. 63
      jode/test/JsrTest.j
  88. 183
      jode/test/LocalTypes.java
  89. 6
      jode/test/Makefile.am
  90. 17
      jode/test/NestedAnon.java
  91. 166
      jode/test/ObfuscateStrings.j
  92. 79
      jode/test/OptimizeTest.java
  93. 58
      jode/test/OptimizerTest.java
  94. 70
      jode/test/RemovePopExample.j
  95. 112
      jode/test/ResolveConflicts.java
  96. 41
      jode/test/StackOps.j
  97. 38
      jode/test/TriadicExpr.java
  98. 159
      jode/test/TryCatch.java
  99. 32
      jode/test/Unreach.java
  100. 7
      jode/test/removepop.jodescript
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,2 +0,0 @@
Makefile
Makefile.in

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,754 +0,0 @@
/* Interpreter Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
import jode.AssertError;
import jode.GlobalOptions;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.Handler;
import jode.bytecode.Instruction;
import jode.bytecode.Opcodes;
import jode.bytecode.Reference;
import jode.bytecode.TypeSignature;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import @COLLECTIONS@.Arrays;
/**
* This class is a java virtual machine written in java :-). Well not
* exactly. It does only handle a subset of the opcodes and is mainly
* written do deobfuscate Strings.
*
* @author Jochen Hoenicke
*/
public class Interpreter implements Opcodes {
private final static int CMP_EQ = 0;
private final static int CMP_NE = 1;
private final static int CMP_LT = 2;
private final static int CMP_GE = 3;
private final static int CMP_GT = 4;
private final static int CMP_LE = 5;
private final static int CMP_GREATER_MASK
= (1 << CMP_GT)|(1 << CMP_GE)|(1 << CMP_NE);
private final static int CMP_LESS_MASK
= (1 << CMP_LT)|(1 << CMP_LE)|(1 << CMP_NE);
private final static int CMP_EQUAL_MASK
= (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ);
private RuntimeEnvironment env;
public Interpreter(RuntimeEnvironment env) {
this.env = env;
}
private Value[] fillParameters(BytecodeInfo code,
Object cls, Object[] params) {
Value[] locals = new Value[code.getMaxLocals()];
for (int i=0; i< locals.length; i++)
locals[i] = new Value();
String myType = code.getMethodInfo().getType();
String[] myParamTypes = TypeSignature.getParameterTypes(myType);
int slot = 0;
if (!code.getMethodInfo().isStatic())
locals[slot++].setObject(cls);
for (int i=0; i< myParamTypes.length; i++) {
locals[slot].setObject(params[i]);
slot += TypeSignature.getTypeSize(myParamTypes[i]);
}
return locals;
}
public Object interpretMethod(BytecodeInfo code,
Object instance, Object[] myParams)
throws InterpreterException, InvocationTargetException {
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INTERPRT) != 0)
GlobalOptions.err.println("Interpreting "+code);
Value[] locals = fillParameters(code, instance, myParams);
Value[] stack = new Value[code.getMaxStack()];
for (int i=0; i < stack.length; i++)
stack[i] = new Value();
Instruction pc = (Instruction) code.getInstructions().get(0);
int stacktop = 0;
big_loop:
for(;;) {
try {
Instruction instr = pc;
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_INTERPRT) != 0) {
GlobalOptions.err.println(instr.getDescription());
GlobalOptions.err.print("stack: [");
for (int i=0; i<stacktop; i++) {
if (i>0)
GlobalOptions.err.print(",");
GlobalOptions.err.print(stack[i]);
if (stack[i].objectValue() instanceof char[]) {
GlobalOptions.err.print
(new String((char[])stack[i].objectValue()));
}
}
GlobalOptions.err.println("]");
GlobalOptions.err.print("local: [");
for (int i=0; i<locals.length; i++)
GlobalOptions.err.print(locals[i]+",");
GlobalOptions.err.println("]");
}
pc = instr.getNextByAddr();
int opcode = instr.getOpcode();
switch (opcode) {
case opc_nop:
break;
case opc_ldc:
stack[stacktop++].setObject(instr.getConstant());
break;
case opc_ldc2_w:
stack[stacktop].setObject(instr.getConstant());
stacktop += 2;
break;
case opc_iload: case opc_fload: case opc_aload:
stack[stacktop++].setValue(locals[instr.getLocalSlot()]);
break;
case opc_lload: case opc_dload:
stack[stacktop].setValue(locals[instr.getLocalSlot()]);
stacktop += 2;
break;
case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload: {
int index = stack[--stacktop].intValue();
Object array = stack[--stacktop].objectValue();
Object result;
try {
switch(opcode) {
case opc_baload:
result = new Integer
(array instanceof byte[]
? ((byte[])array)[index]
: ((boolean[])array)[index] ? 1 : 0);
break;
case opc_caload:
result = new Integer(((char[])array)[index]);
break;
case opc_saload:
result = new Integer(((short[])array)[index]);
break;
default:
result = Array.get(array, index);
break;
}
} catch (NullPointerException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new InvocationTargetException(ex);
}
stack[stacktop++].setObject(result);
if (opcode == opc_laload || opcode == opc_daload)
stacktop++;
break;
}
case opc_istore: case opc_fstore: case opc_astore:
locals[instr.getLocalSlot()].setValue(stack[--stacktop]);
break;
case opc_lstore: case opc_dstore:
locals[instr.getLocalSlot()].setValue(stack[stacktop -= 2]);
break;
case opc_lastore: case opc_dastore:
stacktop--;
/* fall through */
case opc_iastore: case opc_fastore: case opc_aastore:
case opc_bastore: case opc_castore: case opc_sastore: {
Value value = stack[--stacktop];
int index = stack[--stacktop].intValue();
Object array = stack[--stacktop].objectValue();
try {
switch(opcode) {
case opc_bastore:
if (array instanceof byte[])
((byte[])array)[index]
= (byte) value.intValue();
else
((boolean[])array)[index]
= value.intValue() != 0;
break;
case opc_castore:
((char[])array)[index] = (char) value.intValue();
break;
case opc_sastore:
((short[])array)[index] = (short) value.intValue();
break;
default:
Array.set(array, index, value.objectValue());
}
} catch (NullPointerException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayIndexOutOfBoundsException ex) {
throw new InvocationTargetException(ex);
} catch (ArrayStoreException ex) {
throw new InvocationTargetException(ex);
}
break;
}
case opc_pop: case opc_pop2:
stacktop -= opcode - (opc_pop-1);
break;
case opc_dup: case opc_dup_x1: case opc_dup_x2: {
int depth = opcode - opc_dup;
for (int i=0; i < depth+1; i++)
stack[stacktop-i].setValue(stack[stacktop-i-1]);
stack[stacktop-depth-1].setValue(stack[stacktop]);
stacktop++;
break;
}
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2: {
int depth = opcode - opc_dup2;
for (int i=0; i < depth+2; i++)
stack[stacktop+1-i].setValue(stack[stacktop-1-i]);
stack[stacktop-depth-1].setValue(stack[stacktop+1]);
stack[stacktop-depth-2].setValue(stack[stacktop]);
stacktop += 2;
break;
}
case opc_swap: {
Value tmp = stack[stacktop-1];
stack[stacktop-1] = stack[stacktop-2];
stack[stacktop-2] = tmp;
break;
}
case opc_iadd:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
+ stack[stacktop-1].intValue());
stacktop--;
break;
case opc_isub:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
- stack[stacktop-1].intValue());
stacktop--;
break;
case opc_imul:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
* stack[stacktop-1].intValue());
stacktop--;
break;
case opc_idiv:
try {
stack[stacktop-2].setInt
(stack[stacktop-2].intValue()
/ stack[stacktop-1].intValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
stacktop--;
break;
case opc_irem:
try {
stack[stacktop-2].setInt
(stack[stacktop-2].intValue()
% stack[stacktop-1].intValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
stacktop--;
break;
case opc_ladd:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
+ stack[stacktop].longValue());
break;
case opc_lsub:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
- stack[stacktop].longValue());
break;
case opc_lmul:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
* stack[stacktop].longValue());
break;
case opc_ldiv:
stacktop-=2;
try {
stack[stacktop-2].setLong
(stack[stacktop-2].longValue()
/ stack[stacktop].longValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
break;
case opc_lrem:
stacktop-=2;
try {
stack[stacktop-2].setLong
(stack[stacktop-2].longValue()
% stack[stacktop].longValue());
} catch (ArithmeticException ex) {
throw new InvocationTargetException(ex);
}
break;
case opc_fadd:
stack[stacktop-2].setFloat(stack[stacktop-2].floatValue()
+ stack[stacktop-1].floatValue());
stacktop--;
break;
case opc_fsub:
stack[stacktop-2].setFloat(stack[stacktop-2].floatValue()
- stack[stacktop-1].floatValue());
stacktop--;
break;
case opc_fmul:
stack[stacktop-2].setFloat(stack[stacktop-2].floatValue()
* stack[stacktop-1].floatValue());
stacktop--;
break;
case opc_fdiv:
stack[stacktop-2].setFloat(stack[stacktop-2].floatValue()
/ stack[stacktop-1].floatValue());
stacktop--;
break;
case opc_frem:
stack[stacktop-2].setFloat(stack[stacktop-2].floatValue()
% stack[stacktop-1].floatValue());
stacktop--;
break;
case opc_dadd:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
+ stack[stacktop].doubleValue());
break;
case opc_dsub:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
- stack[stacktop].doubleValue());
break;
case opc_dmul:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
* stack[stacktop].doubleValue());
break;
case opc_ddiv:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
/ stack[stacktop].doubleValue());
break;
case opc_drem:
stacktop-=2;
stack[stacktop-2].setDouble(stack[stacktop-2].doubleValue()
% stack[stacktop].doubleValue());
break;
case opc_ineg:
stack[stacktop-1].setInt(-stack[stacktop-1].intValue());
break;
case opc_lneg:
stack[stacktop-2].setLong(-stack[stacktop-2].longValue());
break;
case opc_fneg:
stack[stacktop-1].setFloat(-stack[stacktop-1].floatValue());
break;
case opc_dneg:
stack[stacktop-2].setDouble(-stack[stacktop-2].doubleValue());
break;
case opc_ishl:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
<< stack[stacktop-1].intValue());
stacktop--;
break;
case opc_ishr:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
>> stack[stacktop-1].intValue());
stacktop--;
break;
case opc_iushr:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
>>> stack[stacktop-1].intValue());
stacktop--;
break;
case opc_iand:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
& stack[stacktop-1].intValue());
stacktop--;
break;
case opc_ior :
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
| stack[stacktop-1].intValue());
stacktop--;
break;
case opc_ixor:
stack[stacktop-2].setInt(stack[stacktop-2].intValue()
^ stack[stacktop-1].intValue());
stacktop--;
break;
case opc_lshl:
stack[stacktop-3].setLong(stack[stacktop-3].longValue()
<< stack[stacktop-1].intValue());
stacktop--;
break;
case opc_lshr:
stack[stacktop-3].setLong(stack[stacktop-3].longValue()
>> stack[stacktop-1].intValue());
stacktop--;
break;
case opc_lushr:
stack[stacktop-3].setLong(stack[stacktop-3].longValue()
>>> stack[stacktop-1].intValue());
stacktop--;
break;
case opc_land:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
& stack[stacktop].longValue());
break;
case opc_lor :
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
| stack[stacktop].longValue());
break;
case opc_lxor:
stacktop-=2;
stack[stacktop-2].setLong(stack[stacktop-2].longValue()
^ stack[stacktop].longValue());
break;
case opc_iinc:
locals[instr.getLocalSlot()].setInt
(locals[instr.getLocalSlot()].intValue() + instr.getIncrement());
break;
case opc_i2l:
stack[stacktop-1]
.setLong((long)stack[stacktop-1].intValue());
stacktop++;
break;
case opc_i2f:
stack[stacktop-1]
.setFloat((float)stack[stacktop-1].intValue());
break;
case opc_i2d:
stack[stacktop-1]
.setDouble((double)stack[stacktop-1].intValue());
stacktop++;
break;
case opc_l2i:
stacktop--;
stack[stacktop-1]
.setInt((int)stack[stacktop-1].longValue());
break;
case opc_l2f:
stacktop--;
stack[stacktop-1]
.setFloat((float)stack[stacktop-1].longValue());
break;
case opc_l2d:
stack[stacktop-2]
.setDouble((double)stack[stacktop-2].longValue());
break;
case opc_f2i:
stack[stacktop-1]
.setInt((int)stack[stacktop-1].floatValue());
break;
case opc_f2l:
stack[stacktop-1]
.setLong((long)stack[stacktop-1].floatValue());
stacktop++;
break;
case opc_f2d:
stack[stacktop-1]
.setDouble((double)stack[stacktop-1].floatValue());
stacktop++;
break;
case opc_d2i:
stacktop--;
stack[stacktop-1]
.setInt((int)stack[stacktop-1].doubleValue());
break;
case opc_d2l:
stack[stacktop-2]
.setLong((long)stack[stacktop-2].doubleValue());
break;
case opc_d2f:
stacktop--;
stack[stacktop-1]
.setFloat((float)stack[stacktop-1].doubleValue());
break;
case opc_i2b:
stack[stacktop-1]
.setInt((byte)stack[stacktop-1].intValue());
break;
case opc_i2c:
stack[stacktop-1]
.setInt((char)stack[stacktop-1].intValue());
break;
case opc_i2s:
stack[stacktop-1]
.setInt((short)stack[stacktop-1].intValue());
break;
case opc_lcmp: {
stacktop -= 3;
long val1 = stack[stacktop-1].longValue();
long val2 = stack[stacktop+1].longValue();
stack[stacktop-1].setInt
(val1 == val2 ? 0 : val1 < val2 ? -1 : 1);
break;
}
case opc_fcmpl: case opc_fcmpg: {
float val1 = stack[stacktop-2].floatValue();
float val2 = stack[--stacktop].floatValue();
stack[stacktop-1].setInt
(val1 == val2 ? 0
: ( opcode == opc_fcmpg
? (val1 < val2 ? -1 : 1)
: (val1 > val2 ? 1 : -1)));
break;
}
case opc_dcmpl: case opc_dcmpg: {
stacktop -= 3;
double val1 = stack[stacktop-1].doubleValue();
double val2 = stack[stacktop+1].doubleValue();
stack[stacktop-1].setInt
(val1 == val2 ? 0
: ( opcode == opc_dcmpg
? (val1 < val2 ? -1 : 1)
: (val1 > val2 ? 1 : -1)));
break;
}
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne:
case opc_ifnull: case opc_ifnonnull: {
int value;
if (opcode >= opc_if_acmpeq) {
Object objValue = stack[--stacktop].objectValue();
if (opcode >= opc_ifnull) {
value = objValue == null ? 0 : 1;
opcode -= opc_ifnull;
} else {
value = objValue
== stack[--stacktop].objectValue() ? 0 : 1;
opcode -= opc_if_acmpeq;
}
} else {
value = stack[--stacktop].intValue();
if (opcode >= opc_if_icmpeq) {
int val1 = stack[--stacktop].intValue();
value = (val1 == value ? 0
: val1 < value ? -1 : 1);
opcode -= opc_if_icmpeq;
} else
opcode -= opc_ifeq;
}
int opc_mask = 1 << opcode;
if (value > 0 && (opc_mask & CMP_GREATER_MASK) != 0
|| value < 0 && (opc_mask & CMP_LESS_MASK) != 0
|| value == 0 && (opc_mask & CMP_EQUAL_MASK) != 0)
pc = instr.getSingleSucc();
break;
}
case opc_jsr:
case opc_jsr_w:
stack[stacktop++].setObject(instr);
/* fall through */
case opc_goto:
case opc_goto_w:
pc = instr.getSingleSucc();
break;
case opc_ret:
pc = (Instruction)locals[instr.getLocalSlot()].objectValue();
break;
case opc_lookupswitch: {
int value = stack[--stacktop].intValue();
int[] values = instr.getValues();
int pos = Arrays.binarySearch(values, value);
pc = pos < 0
? instr.getSuccs()[values.length]
: instr.getSuccs()[pos];
break;
}
case opc_ireturn: case opc_freturn: case opc_areturn:
return stack[--stacktop].objectValue();
case opc_lreturn: case opc_dreturn:
return stack[stacktop -= 2].objectValue();
case opc_return:
return Void.TYPE;
case opc_getstatic: {
Reference ref = instr.getReference();
Object result = env.getField(instr.getReference(), null);
stack[stacktop].setObject(result);
stacktop += TypeSignature.getTypeSize(ref.getType());
break;
}
case opc_getfield: {
Reference ref = instr.getReference();
Object cls = stack[--stacktop].objectValue();
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
Object result = env.getField(instr.getReference(), cls);
stack[stacktop].setObject(result);
stacktop += TypeSignature.getTypeSize(ref.getType());
break;
}
case opc_putstatic: {
Reference ref = instr.getReference();
stacktop -= TypeSignature.getTypeSize(ref.getType());
Object value = stack[stacktop].objectValue();
env.putField(instr.getReference(), null, value);
break;
}
case opc_putfield: {
Reference ref = instr.getReference();
stacktop -= TypeSignature.getTypeSize(ref.getType());
Object value = stack[stacktop].objectValue();
Object cls = stack[--stacktop].objectValue();
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
env.putField(instr.getReference(), cls, value);
break;
}
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic :
case opc_invokeinterface: {
Reference ref = instr.getReference();
String[] paramTypes
= TypeSignature.getParameterTypes(ref.getType());
Object[] args = new Object[paramTypes.length];
for (int i = paramTypes.length - 1; i >= 0; i--) {
stacktop -= TypeSignature.getTypeSize(paramTypes[i]);
args[i] = stack[stacktop].objectValue();
}
Object result = null;
if (opcode == opc_invokespecial
&& ref.getName().equals("<init>")
&& stack[--stacktop].getNewObject() != null) {
NewObject newObj = stack[stacktop].getNewObject();
if (!newObj.getType().equals(ref.getClazz()))
throw new InterpreterException
("constructor doesn't match new");
newObj.setObject(env.invokeConstructor(ref, args));
} else if (opcode == opc_invokestatic) {
result = env.invokeMethod(ref, false, null, args);
} else {
Object cls = stack[--stacktop].objectValue();
if (cls == null)
throw new InvocationTargetException
(new NullPointerException());
result = env.invokeMethod
(ref, opcode != opc_invokespecial, cls, args);
}
String retType
= TypeSignature.getReturnType(ref.getType());
if (!retType.equals("V")) {
stack[stacktop].setObject(result);
stacktop += TypeSignature.getTypeSize(retType);
}
break;
}
case opc_new: {
String clazz = instr.getClazzType();
stack[stacktop++].setNewObject(new NewObject(clazz));
break;
}
case opc_arraylength: {
Object array = stack[--stacktop].objectValue();
if (array == null)
throw new InvocationTargetException
(new NullPointerException());
stack[stacktop++].setInt(Array.getLength(array));
break;
}
case opc_athrow: {
Throwable exc =
(Throwable) stack[--stacktop].objectValue();
throw new InvocationTargetException
(exc == null ? new NullPointerException() : exc);
}
case opc_checkcast: {
Object obj = stack[stacktop-1].objectValue();
if (obj != null
&& !env.instanceOf(obj, instr.getClazzType()))
throw new InvocationTargetException
(new ClassCastException(obj.getClass().getName()));
break;
}
case opc_instanceof: {
Object obj = stack[--stacktop].objectValue();
stack[stacktop++].setInt
(env.instanceOf(obj, instr.getClazzType()) ? 1 : 0);
break;
}
case opc_monitorenter:
env.enterMonitor(stack[--stacktop].objectValue());
break;
case opc_monitorexit:
env.exitMonitor(stack[--stacktop].objectValue());
break;
case opc_multianewarray: {
int dimension = instr.getDimensions();
int[] dims = new int[dimension];
for (int i=dimension - 1; i >= 0; i--)
dims[i] = stack[--stacktop].intValue();
try {
stack[stacktop++].setObject
(env.newArray(instr.getClazzType(), dims));
} catch (NegativeArraySizeException ex) {
throw new InvocationTargetException(ex);
}
break;
}
default:
throw new AssertError("Invalid opcode "+opcode);
}
} catch (InvocationTargetException ex) {
Handler[] handlers = code.getExceptionHandlers();
Throwable obj = ex.getTargetException();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].start.compareTo(pc) <= 0
&& handlers[i].end.compareTo(pc) >= 0
&& (handlers[i].type == null
|| env.instanceOf(obj, handlers[i].type))) {
stacktop = 0;
stack[stacktop++].setObject(obj);
pc = handlers[i].catcher;
continue big_loop;
}
}
throw ex;
}
}
}
}

@ -1,35 +0,0 @@
/* InterpreterException Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
/**
* This exception is thrown by the interpreter on various conditions.
*
* @author Jochen Hoenicke
*/
public class InterpreterException extends Exception {
public InterpreterException(String detail) {
super(detail);
}
public InterpreterException() {
super();
}
}

@ -1,36 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir)
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \
CodeVerifier.java \
Interpreter.java \
InterpreterException.java \
NewObject.java \
RuntimeEnvironment.java \
SimpleRuntimeEnvironment.java \
SyntheticAnalyzer.java \
Value.java \
VerifyException.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include $(MY_JAVA_FILES:.java=.dep)
%.class: %.java
$(JAVAC) -classpath `$(SUBSTCP) $(BUILD_CLASSPATH):$(CLASSLIB)` -d $(top_builddir) $<
%.dep: %.class
$(JAVADEP) $< >$@
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,54 +0,0 @@
/* NewObject Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
/**
* This class represents a new object, that may not be initialized yet.
*
* @author Jochen Hoenicke
*/
public class NewObject {
Object instance;
String type;
public NewObject(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setObject(Object obj) {
instance = obj;
}
public Object objectValue() {
return instance;
}
public String toString() {
if (instance == null)
return "new "+type;
else
return instance.toString();
}
}

@ -1,121 +0,0 @@
/* RuntimeEnvironment Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
import jode.bytecode.Reference;
import java.lang.reflect.InvocationTargetException;
/**
* This interface is used by the Interpreter to actually modify objects,
* invoke methods, etc. <br>
*
* The objects used in this runtime environment need not to be of the
* real type, but can be some other type of your choice. But some
* mappings must be preserved, since they are used inside the
* Interpreter:
* <ul> <li>boolean, byte, short, char and int are mapped to Integer. </li>
* <li> float, long, double are mapped to Float, Long, Double resp. </li>
* <li> array of primitive type is mapped to itself (not array of Integer)</li>
* <li> array of other types are mapped to array of mapped other type </li>
* </ul>
*
* @author Jochen Hoenicke */
public interface RuntimeEnvironment {
/**
* Get the value of a field member.
* @param fieldref the Reference of the field.
* @param obj the object of which the field should be taken, null
* if the field is static.
* @return the field value. Primitive types are wrapped to
* Object.
* @exception InterpreterException if the field does not exists, the
* object is not supported etc.
*/
public Object getField(Reference fieldref, Object obj)
throws InterpreterException;
/**
* Set the value of a field member.
* @param fieldref the Reference of the field.
* @param obj the object of which the field should be taken, null
* if the field is static.
* @param value the field value. Primitive types are wrapped to
* Object.
* @exception InterpreterException if the field does not exists, the
* object is not supported etc.
*/
public void putField(Reference fieldref, Object obj, Object value)
throws InterpreterException;
/**
* Invoke a method.
* @param methodRef the reference to the method.
* @param isVirtual true, iff the call is virtual
* @param cls the object on which the method should be called, null
* if the method is static.
* @param params the params of the method.
* @return the return value of the method. Void type is ignored,
* may be null.
* @exception InterpreterException if the field does not exists, the
* object is not supported etc. */
public Object invokeMethod(Reference methodRef, boolean isVirtual,
Object cls, Object[] params)
throws InterpreterException, InvocationTargetException;
/**
* Create a new instance of an object.
* @param methodRef the reference of the constructor to invoke
* @param params the params of the method.
* @return the new object.
*/
public Object invokeConstructor(Reference methodRef, Object[] params)
throws InterpreterException, InvocationTargetException;
/**
* Check if obj is an instance of className
* @param className the type signature of the class.
* @return true, if obj is an instance of className, false otherwise.
*/
public boolean instanceOf(Object obj, String className)
throws InterpreterException;
/**
* Create a new multidimensional Array.
* @param type the type of the elements.
* @param dimensions the size in every dimension.
* @return the new array (this must be an array, see class comment).
*/
public Object newArray(String type, int[] dimensions)
throws InterpreterException;
/**
* Enter a monitor.
* @param object the object whose monitor should be taken.
*/
public void enterMonitor(Object obj)
throws InterpreterException;
/**
* Exit a monitor.
* @param object the object whose monitor should be freed.
*/
public void exitMonitor(Object obj)
throws InterpreterException;
}

@ -1,231 +0,0 @@
/* SimpleRuntimeEnvironment Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
import jode.AssertError;
import jode.bytecode.Reference;
import jode.bytecode.TypeSignature;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class SimpleRuntimeEnvironment implements RuntimeEnvironment {
public static Object fromReflectType(String typeSig, Object value) {
switch(typeSig.charAt(0)) {
case 'Z':
return new Integer(((Boolean) value).booleanValue() ? 1 : 0);
case 'B':
case 'S':
return new Integer(((Number) value).intValue());
case 'C':
return new Integer(((Character) value).charValue());
default:
return value;
}
}
public static Object toReflectType(String typeSig, Object value) {
switch(typeSig.charAt(0)) {
case 'Z':
return new Boolean(((Integer)value).intValue() != 0);
case 'B':
return new Byte(((Integer)value).byteValue());
case 'S':
return new Short(((Integer)value).shortValue());
case 'C':
return new Character((char) ((Integer)value).intValue());
default:
return value;
}
}
public Object getField(Reference ref, Object obj)
throws InterpreterException {
Field f;
try {
Class clazz = TypeSignature.getClass(ref.getClazz());
try {
f = clazz.getField(ref.getName());
} catch (NoSuchFieldException ex) {
f = clazz.getDeclaredField(ref.getName());
}
} catch (ClassNotFoundException ex) {
throw new InterpreterException
(ref+": Class not found");
} catch (NoSuchFieldException ex) {
throw new InterpreterException
("Constructor "+ref+" not found");
} catch (SecurityException ex) {
throw new InterpreterException
(ref+": Security exception");
}
try {
return fromReflectType(ref.getType(), f.get(obj));
} catch (IllegalAccessException ex) {
throw new InterpreterException
("Field " + ref + " not accessible");
}
}
public void putField(Reference ref, Object obj, Object value)
throws InterpreterException {
Field f;
try {
Class clazz = TypeSignature.getClass(ref.getClazz());
try {
f = clazz.getField(ref.getName());
} catch (NoSuchFieldException ex) {
f = clazz.getDeclaredField(ref.getName());
}
} catch (ClassNotFoundException ex) {
throw new InterpreterException
(ref+": Class not found");
} catch (NoSuchFieldException ex) {
throw new InterpreterException
("Constructor "+ref+" not found");
} catch (SecurityException ex) {
throw new InterpreterException
(ref+": Security exception");
}
try {
f.set(obj, toReflectType(ref.getType(), value));
} catch (IllegalAccessException ex) {
throw new InterpreterException
("Field " + ref + " not accessible");
}
}
public Object invokeConstructor(Reference ref, Object[] params)
throws InterpreterException, InvocationTargetException {
Constructor c;
try {
String[] paramTypeSigs
= TypeSignature.getParameterTypes(ref.getType());
Class clazz = TypeSignature.getClass(ref.getClazz());
Class[] paramTypes = new Class[paramTypeSigs.length];
for (int i=0; i< paramTypeSigs.length; i++) {
params[i] = toReflectType(paramTypeSigs[i], params[i]);
paramTypes[i] = TypeSignature.getClass(paramTypeSigs[i]);
}
try {
c = clazz.getConstructor(paramTypes);
} catch (NoSuchMethodException ex) {
c = clazz.getDeclaredConstructor(paramTypes);
}
} catch (ClassNotFoundException ex) {
throw new InterpreterException
(ref+": Class not found");
} catch (NoSuchMethodException ex) {
throw new InterpreterException
("Constructor "+ref+" not found");
} catch (SecurityException ex) {
throw new InterpreterException
(ref+": Security exception");
}
try {
return c.newInstance(params);
} catch (IllegalAccessException ex) {
throw new InterpreterException
("Constructor " + ref + " not accessible");
} catch (InstantiationException ex) {
throw new InterpreterException
("InstantiationException in " + ref + ".");
}
}
public Object invokeMethod(Reference ref, boolean isVirtual,
Object cls, Object[] params)
throws InterpreterException, InvocationTargetException {
if (!isVirtual && cls != null) /*XXX*/
throw new InterpreterException
("Can't invoke nonvirtual Method " + ref + ".");
Method m;
try {
String[] paramTypeSigs
= TypeSignature.getParameterTypes(ref.getType());
Class clazz = TypeSignature.getClass(ref.getClazz());
Class[] paramTypes = new Class[paramTypeSigs.length];
for (int i=0; i< paramTypeSigs.length; i++) {
params[i] = toReflectType(paramTypeSigs[i], params[i]);
paramTypes[i] = TypeSignature.getClass(paramTypeSigs[i]);
}
try {
m = clazz.getMethod(ref.getName(), paramTypes);
} catch (NoSuchMethodException ex) {
m = clazz.getDeclaredMethod(ref.getName(), paramTypes);
}
} catch (ClassNotFoundException ex) {
throw new InterpreterException
(ref+": Class not found");
} catch (NoSuchMethodException ex) {
throw new InterpreterException
("Method "+ref+" not found");
} catch (SecurityException ex) {
throw new InterpreterException
(ref+": Security exception");
}
String retType = TypeSignature.getReturnType(ref.getType());
try {
return fromReflectType(retType, m.invoke(cls, params));
} catch (IllegalAccessException ex) {
throw new InterpreterException
("Method " + ref + " not accessible");
}
}
public boolean instanceOf(Object obj, String className)
throws InterpreterException {
Class clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
}
return obj != null && !clazz.isInstance(obj);
}
public Object newArray(String type, int[] dimensions)
throws InterpreterException, NegativeArraySizeException {
Class clazz;
try {
/* get the base class (strip leading "[") */
clazz = TypeSignature.getClass(type.substring(dimensions.length));
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
}
return Array.newInstance(clazz, dimensions);
}
public void enterMonitor(Object obj)
throws InterpreterException {
throw new InterpreterException("monitor not implemented");
}
public void exitMonitor(Object obj)
throws InterpreterException {
throw new InterpreterException("monitor not implemented");
}
}

@ -1,327 +0,0 @@
/* SyntheticAnalyzer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
import jode.GlobalOptions;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.Handler;
import jode.bytecode.Instruction;
import jode.bytecode.MethodInfo;
import jode.bytecode.Opcodes;
import jode.bytecode.Reference;
import jode.type.Type;
import jode.type.MethodType;
import java.lang.reflect.Modifier;
import @COLLECTIONS@.Iterator;
public class SyntheticAnalyzer implements Opcodes {
public final static int UNKNOWN = 0;
public final static int GETCLASS = 1;
public final static int ACCESSGETFIELD = 2;
public final static int ACCESSPUTFIELD = 3;
public final static int ACCESSMETHOD = 4;
public final static int ACCESSGETSTATIC = 5;
public final static int ACCESSPUTSTATIC = 6;
public final static int ACCESSSTATICMETHOD = 7;
int kind = UNKNOWN;
Reference reference;
MethodInfo method;
public SyntheticAnalyzer(MethodInfo method, boolean checkName) {
this.method = method;
if (method.getBytecode() == null)
return;
if (!checkName || method.getName().equals("class$"))
if (checkGetClass())
return;
if (!checkName || method.getName().startsWith("access$"))
if (checkAccess())
return;
}
public int getKind() {
return kind;
}
public Reference getReference() {
return reference;
}
private static final int[] getClassOpcodes = {
opc_aload, opc_invokestatic, opc_areturn,
opc_astore, opc_new, opc_dup, opc_aload,
opc_invokevirtual, opc_invokespecial, opc_athrow
};
private static final Reference[] getClassRefs = {
null, Reference.getReference("Ljava/lang/Class;", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;"),
null, null, null, null, null,
Reference.getReference("Ljava/lang/Throwable;", "getMessage",
"()Ljava/lang/String;"),
Reference.getReference("Ljava/lang/NoClassDefFoundError;", "<init>",
"(Ljava/lang/String;)V"), null
};
boolean checkGetClass() {
if (!method.isStatic()
|| !(method.getType()
.equals("(Ljava/lang/String;)Ljava/lang/Class;")))
return false;
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers.length != 1
|| !"java.lang.ClassNotFoundException".equals(excHandlers[0].type))
return false;
int excSlot = -1;
int i = 0;
for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); i++) {
Instruction instr = (Instruction) iter.next();
if (i == getClassOpcodes.length
|| instr.getOpcode() != getClassOpcodes[i])
return false;
if (i == 0 && (instr.getLocalSlot() != 0
|| excHandlers[0].start != instr))
return false;
if (i == 2 && excHandlers[0].end != instr)
return false;
if (i == 3) {
if (excHandlers[0].catcher != instr)
return false;
excSlot = instr.getLocalSlot();
}
if (i == 4 && !instr.getClazzType().equals
("Ljava/lang/NoClassDefFoundError;"))
return false;
if (i == 6 && instr.getLocalSlot() != excSlot)
return false;
if (getClassRefs[i] != null
&& !getClassRefs[i].equals(instr.getReference()))
return false;
}
this.kind = GETCLASS;
return true;
}
private final int modifierMask = (Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.PUBLIC | Modifier.STATIC);
public boolean checkStaticAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Iterator iter = bytecode.getInstructions().iterator();
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getstatic) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
if (iter.hasNext())
return false;
/* For valid bytecode the type matches automatically */
reference = ref;
kind = ACCESSGETSTATIC;
return true;
}
int params = 0, slot = 0;
while (instr.getOpcode() >= opc_iload
&& instr.getOpcode() <= opc_aload
&& instr.getLocalSlot() == slot) {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_putstatic) {
if (params != 1)
return false;
/* For valid bytecode the type of param matches automatically */
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC))
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return)
return false;
if (iter.hasNext())
return false;
reference = ref;
kind = ACCESSPUTSTATIC;
return true;
}
if (instr.getOpcode() == opc_invokestatic) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) !=
(Modifier.PRIVATE | Modifier.STATIC)
|| refType.getParameterTypes().length != params)
return false;
instr = (Instruction) iter.next();
if (refType.getReturnType() == Type.tVoid) {
if (instr.getOpcode() != opc_return)
return false;
} else {
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
}
if (iter.hasNext())
return false;
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSSTATICMETHOD;
return true;
}
return false;
}
public boolean checkAccess() {
ClassInfo clazzInfo = method.getClazzInfo();
BytecodeInfo bytecode = method.getBytecode();
Handler[] excHandlers = bytecode.getExceptionHandlers();
if (excHandlers != null && excHandlers.length != 0)
return false;
if (method.isStatic()) {
if (checkStaticAccess())
return true;
}
Iterator iter = bytecode.getInstructions().iterator();
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_aload || instr.getLocalSlot() != 0)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getfield) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
if (iter.hasNext())
return false;
/* For valid bytecode the type matches automatically */
reference = ref;
kind = ACCESSGETFIELD;
return true;
}
int params = 0, slot = 1;
while (instr.getOpcode() >= opc_iload
&& instr.getOpcode() <= opc_aload
&& instr.getLocalSlot() == slot) {
params++;
slot += (instr.getOpcode() == opc_lload
|| instr.getOpcode() == opc_dload) ? 2 : 1;
instr = (Instruction) iter.next();
}
if (instr.getOpcode() == opc_putfield) {
if (params != 1)
return false;
/* For valid bytecode the type of param matches automatically */
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
FieldInfo refField
= clazzInfo.findField(ref.getName(), ref.getType());
if ((refField.getModifiers() & modifierMask) != Modifier.PRIVATE)
return false;
instr = (Instruction) iter.next();
if (instr.getOpcode() != opc_return)
return false;
if (iter.hasNext())
return false;
reference = ref;
kind = ACCESSPUTFIELD;
return true;
}
if (instr.getOpcode() == opc_invokespecial) {
Reference ref = instr.getReference();
String refClazz = ref.getClazz().substring(1);
if (!(refClazz.substring(0, refClazz.length()-1)
.equals(clazzInfo.getName().replace('.','/'))))
return false;
MethodInfo refMethod
= clazzInfo.findMethod(ref.getName(), ref.getType());
MethodType refType = Type.tMethod(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != Modifier.PRIVATE
|| refType.getParameterTypes().length != params)
return false;
instr = (Instruction) iter.next();
if (refType.getReturnType() == Type.tVoid) {
if (instr.getOpcode() != opc_return)
return false;
} else {
if (instr.getOpcode() < opc_ireturn
|| instr.getOpcode() > opc_areturn)
return false;
}
if (iter.hasNext())
return false;
/* For valid bytecode the types matches automatically */
reference = ref;
kind = ACCESSMETHOD;
return true;
}
return false;
}
}

@ -1,98 +0,0 @@
/* Value Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
import jode.bytecode.*;
/**
* This class represents a stack value.
*
* @author Jochen Hoenicke
*/
class Value {
Object value;
NewObject newObj;
public Value() {
}
public void setObject(Object obj) {
newObj = null;
value = obj;
}
public Object objectValue() {
if (newObj != null)
return newObj.objectValue();
return value;
}
public void setInt(int i) {
newObj = null;
value = new Integer(i);
}
public int intValue() {
return ((Integer)value).intValue();
}
public void setLong(long i) {
newObj = null;
value = new Long(i);
}
public long longValue() {
return ((Long)value).longValue();
}
public void setFloat(float i) {
newObj = null;
value = new Float(i);
}
public float floatValue() {
return ((Float)value).floatValue();
}
public void setDouble(double i) {
newObj = null;
value = new Double(i);
}
public double doubleValue() {
return ((Double)value).doubleValue();
}
public void setNewObject(NewObject n) {
newObj = n;
}
public NewObject getNewObject() {
return newObj;
}
public void setValue(Value val) {
value = val.value;
newObj = val.newObj;
}
public String toString() {
return newObj != null ? newObj.toString() : ""+value;
}
}

@ -1,36 +0,0 @@
/* VerifyException Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.jvm;
import jode.bytecode.*;
/**
* This exception is thrown by the CodeVerifier on various conditions.
*
* @author Jochen Hoenicke
*/
public class VerifyException extends Exception {
public VerifyException(String detail) {
super(detail);
}
public VerifyException() {
super();
}
}

@ -1,2 +0,0 @@
Makefile
Makefile.in

@ -1,501 +0,0 @@
/* ClassBundle Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.GlobalOptions;
import jode.bytecode.SearchPath;
import jode.bytecode.ClassInfo;
import jode.bytecode.Reference;
import java.io.*;
import java.util.zip.ZipOutputStream;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashSet;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.TreeMap;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
///#ifdef JDK12
///import @COLLECTIONS@.WeakHashMap;
///#else
import @COLLECTIONS@.HashMap;
///#endif
public class ClassBundle implements OptionHandler {
PackageIdentifier basePackage;
/**
* the identifiers that must be analyzed.
*/
Set toAnalyze = new HashSet();
String classPath;
String destDir;
String tableFile;
String toTableFile;
IdentifierMatcher loading;
IdentifierMatcher preserving;
IdentifierMatcher reaching;
CodeTransformer[] preTrafos;
CodeAnalyzer analyzer;
CodeTransformer[] postTrafos;
Renamer renamer;
public ClassBundle() {
classPath = System.getProperty("java.class.path")
.replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar);
destDir = ".";
basePackage = new PackageIdentifier(this, null, "", "");
basePackage.setReachable();
basePackage.setPreserved();
}
///#ifdef JDK12
/// private static final Map aliasesHash = new WeakHashMap();
///#else
private static final Map aliasesHash = new HashMap();
///#endif
private static final Map clazzCache = new HashMap();
private static final Map referenceCache = new HashMap();
public static void setStripOptions(Collection stripString) {
}
public void setOption(String option, Collection values) {
if (option.equals("classpath")) {
Iterator i = values.iterator();
StringBuffer sb = new StringBuffer((String) i.next());
while (i.hasNext()) {
sb.append(SearchPath.pathSeparatorChar)
.append((String)i.next());
}
ClassInfo.setClassPath(sb.toString());
return;
}
if (option.equals("dest")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one destination path allowed");
destDir = (String) values.iterator().next();
return;
}
if (option.equals("table")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one destination path allowed");
tableFile = (String) values.iterator().next();
return;
}
if (option.equals("revtable")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one destination path allowed");
toTableFile = (String) values.iterator().next();
return;
}
if (option.equals("strip")) {
next_token:
for (Iterator iter = values.iterator(); iter.hasNext(); ) {
String token = (String) iter.next();
for (int i=0; i < Main.stripNames.length; i++) {
if (token.equals(Main.stripNames[i])) {
Main.stripping |= 1 << i;
continue next_token;
}
}
throw new IllegalArgumentException("Unknown strip option: `"
+token+"'");
}
return;
}
if (option.equals("load")) {
if (values.size() == 1) {
Object value = values.iterator().next();
if (value instanceof String)
loading = new WildCard((String)value);
else
loading = (IdentifierMatcher) value;
} else {
IdentifierMatcher[] matchers
= new IdentifierMatcher[values.size()];
int j = 0;
for (Iterator i = values.iterator(); i.hasNext(); ) {
Object value = i.next();
matchers[j++] = (value instanceof String
? new WildCard((String)value)
: (IdentifierMatcher) value);
}
loading = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, matchers);
}
return;
}
if (option.equals("preserve")) {
if (values.size() == 1) {
Object value = values.iterator().next();
if (value instanceof String)
preserving = new WildCard((String)value);
else
preserving = (IdentifierMatcher) value;
} else {
IdentifierMatcher[] matchers
= new IdentifierMatcher[values.size()];
int j = 0;
for (Iterator i = values.iterator(); i.hasNext(); ) {
Object value = i.next();
matchers[j++] = (value instanceof String
? new WildCard((String)value)
: (IdentifierMatcher) value);
}
preserving = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, matchers);
}
return;
}
if (option.equals("reach")) {
// NOT IMPLEMENTED YET
if (values.size() == 1) {
Object value = values.iterator().next();
if (value instanceof String)
reaching = new WildCard((String)value);
else
reaching = (IdentifierMatcher) value;
} else {
IdentifierMatcher[] matchers
= new IdentifierMatcher[values.size()];
int j = 0;
for (Iterator i = values.iterator(); i.hasNext(); ) {
Object value = i.next();
matchers[j++] = (value instanceof String
? new WildCard((String)value)
: (IdentifierMatcher) value);
}
reaching = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, matchers);
}
}
if (option.equals("pre")) {
preTrafos = (CodeTransformer[])
values.toArray(new CodeTransformer[values.size()]);
return;
}
if (option.equals("analyzer")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one analyzer is allowed");
analyzer = (CodeAnalyzer) values.iterator().next();
return;
}
if (option.equals("post")) {
postTrafos = (CodeTransformer[])
values.toArray(new CodeTransformer[values.size()]);
return;
}
if (option.equals("renamer")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Only one renamer allowed");
renamer = (Renamer) values.iterator().next();
return;
}
throw new IllegalArgumentException("Invalid option `"+option+"'.");
}
public Reference getReferenceAlias(Reference ref) {
Reference alias = (Reference) aliasesHash.get(ref);
if (alias == null) {
Identifier ident = getIdentifier(ref);
String newType = getTypeAlias(ref.getType());
if (ident == null)
alias = Reference.getReference
(ref.getClazz(), ref.getName(), newType);
else
alias = Reference.getReference
("L"+ident.getParent().getFullAlias().replace('.','/')+';',
ident.getAlias(), newType);
aliasesHash.put(ref, alias);
}
return alias;
}
public String getTypeAlias(String typeSig) {
String alias = (String) aliasesHash.get(typeSig);
if (alias == null) {
StringBuffer newSig = new StringBuffer();
int index = 0, nextindex;
while ((nextindex = typeSig.indexOf('L', index)) != -1) {
newSig.append(typeSig.substring(index, nextindex+1));
index = typeSig.indexOf(';', nextindex);
String typeAlias = basePackage.findAlias
(typeSig.substring(nextindex+1, index).replace('/','.'));
newSig.append(typeAlias.replace('.', '/'));
}
alias = newSig.append(typeSig.substring(index))
.toString().intern();
aliasesHash.put(typeSig, alias);
}
return alias;
}
public void addClassIdentifier(Identifier ident) {
}
public ClassIdentifier getClassIdentifier(String name) {
if (clazzCache.containsKey(name))
return (ClassIdentifier) clazzCache.get(name);
ClassIdentifier ident
= (ClassIdentifier) basePackage.getIdentifier(name);
clazzCache.put(name, ident);
return ident;
}
public Identifier getIdentifier(Reference ref) {
if (referenceCache.containsKey(ref))
return (Identifier) referenceCache.get(ref);
String clName = ref.getClazz();
if (clName.charAt(0) == '[')
/* Can't represent arrays */
return null;
ClassIdentifier clazzIdent =
getClassIdentifier(clName.substring(1, clName.length()-1)
.replace('/','.'));
Identifier ident =
clazzIdent == null ? null
: clazzIdent.getIdentifier(ref.getName(), ref.getType());
referenceCache.put(ref, ident);
return ident;
}
public void reachableClass(String clazzName) {
ClassIdentifier ident = getClassIdentifier(clazzName);
if (ident != null)
ident.setReachable();
}
public void reachableReference(Reference ref, boolean isVirtual) {
String clName = ref.getClazz();
if (clName.charAt(0) == '[')
/* Can't represent arrays */
return;
ClassIdentifier ident =
getClassIdentifier(clName.substring(1, clName.length()-1)
.replace('/','.'));
if (ident != null)
ident.reachableReference(ref, isVirtual);
}
public void analyzeIdentifier(Identifier ident) {
if (ident == null)
throw new NullPointerException();
toAnalyze.add(ident);
}
public void analyze() {
while(!toAnalyze.isEmpty()) {
Identifier ident = (Identifier) toAnalyze.iterator().next();
toAnalyze.remove(ident);
ident.analyze();
}
}
public IdentifierMatcher getPreserveRule() {
return preserving;
}
public CodeAnalyzer getCodeAnalyzer() {
return analyzer;
}
public CodeTransformer[] getPreTransformers() {
return preTrafos;
}
public CodeTransformer[] getPostTransformers() {
return postTrafos;
}
public void buildTable(Renamer renameRule) {
basePackage.buildTable(renameRule);
}
public void readTable() {
try {
TranslationTable table = new TranslationTable();
InputStream input = new FileInputStream(tableFile);
table.load(input);
input.close();
basePackage.readTable(table);
} catch (java.io.IOException ex) {
GlobalOptions.err.println("Can't read rename table " + tableFile);
ex.printStackTrace(GlobalOptions.err);
}
}
public void writeTable() {
TranslationTable table = new TranslationTable();
basePackage.writeTable(table);
try {
OutputStream out = new FileOutputStream(toTableFile);
table.store(out);
out.close();
} catch (java.io.IOException ex) {
GlobalOptions.err.println("Can't write rename table "+toTableFile);
ex.printStackTrace(GlobalOptions.err);
}
}
public void doTransformations() {
basePackage.doTransformations();
}
public void storeClasses() {
if (destDir.endsWith(".jar") ||
destDir.endsWith(".zip")) {
try {
ZipOutputStream zip = new ZipOutputStream
(new FileOutputStream(destDir));
basePackage.storeClasses(zip);
zip.close();
} catch (IOException ex) {
GlobalOptions.err.println
("Can't write zip file: "+destDir);
ex.printStackTrace(GlobalOptions.err);
}
} else {
File directory = new File(destDir);
if (!directory.exists()) {
GlobalOptions.err.println("Destination directory "
+directory.getPath()
+" doesn't exists.");
return;
}
basePackage.storeClasses(new File(destDir));
}
}
public void run() {
if (analyzer == null)
analyzer = new SimpleAnalyzer();
if (preTrafos == null)
preTrafos = new CodeTransformer[0];
if (postTrafos == null)
postTrafos = new CodeTransformer[0];
if (renamer == null)
renamer = new Renamer() {
public Iterator generateNames(Identifier ident) {
final String base = ident.getName();
return new Iterator() {
int last = 0;
public boolean hasNext() {
return true;
}
public Object next() {
return (last++ == 0 ? base : base + last);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory();
long last;
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used before: "+(runtime.totalMemory()- free));
GlobalOptions.err.println("Loading and preserving classes");
long time = System.currentTimeMillis();
basePackage.loadMatchingClasses(loading);
basePackage.applyPreserveRule(preserving);
System.err.println("Time used: "+(System.currentTimeMillis() - time));
GlobalOptions.err.println("Computing reachable settings");
time = System.currentTimeMillis();
analyze();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
free = runtime.freeMemory();
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used after analyze: "
+ (runtime.totalMemory() - free));
GlobalOptions.err.println("Renaming methods");
time = System.currentTimeMillis();
if (tableFile != null)
readTable();
buildTable(renamer);
if (toTableFile != null)
writeTable();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
GlobalOptions.err.println("Transforming the classes");
time = System.currentTimeMillis();
doTransformations();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
free = runtime.freeMemory();
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used after transform: "
+ (runtime.totalMemory() - free));
GlobalOptions.err.println("Writing new classes");
time = System.currentTimeMillis();
storeClasses();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
}
}

@ -1,898 +0,0 @@
/* ClassIdentifier Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.GlobalOptions;
import jode.bytecode.*;
import @COLLECTIONS@.Comparator;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Collections;
import @COLLECTIONS@.ArrayList;
import @COLLECTIONS@.Arrays;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.List;
import @COLLECTIONS@.LinkedList;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.Random;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
import java.lang.reflect.Modifier;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.OutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class ClassIdentifier extends Identifier {
PackageIdentifier pack;
String name;
String fullName;
ClassInfo info;
String superName;
String[] ifaceNames;
List fieldIdents, methodIdents;
List knownSubClasses = new LinkedList();
List virtualReachables = new LinkedList();
public ClassIdentifier(PackageIdentifier pack, String fullName,
String name, ClassInfo info) {
super(name);
this.pack = pack;
this.fullName = fullName;
this.name = name;
this.info = info;
}
public void addSubClass(ClassIdentifier ci) {
knownSubClasses.add(ci);
for(Iterator i = virtualReachables.iterator(); i.hasNext(); )
ci.reachableReference((Reference) i.next(), true);
}
private FieldIdentifier findField(String name, String typeSig) {
for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) {
FieldIdentifier ident = (FieldIdentifier) i.next();
if (ident.getName().equals(name)
&& ident.getType().equals(typeSig))
return ident;
}
return null;
}
private MethodIdentifier findMethod(String name, String typeSig) {
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
MethodIdentifier ident = (MethodIdentifier) i.next();
if (ident.getName().equals(name)
&& ident.getType().equals(typeSig))
return ident;
}
return null;
}
public void reachableReference(Reference ref, boolean isVirtual) {
boolean found = false;
for (Iterator i = getChilds(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (ref.getName().equals(ident.getName())
&& ref.getType().equals(ident.getType())) {
ident.setReachable();
found = true;
}
}
if (!found) {
// This means that the method is inherited from parent and
// must be marked as reachable there, (but not virtual).
// Consider following:
// A method in Collection and AbstractCollection is not reachable
// but it is reachable in Set and not implemented in AbstractSet
// In that case the method must be marked reachable in
// AbstractCollection.
ClassIdentifier superIdent = Main.getClassBundle()
.getClassIdentifier(info.getSuperclass().getName());
if (superIdent != null)
superIdent.reachableReference(ref, false);
}
if (isVirtual) {
for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) {
Reference prevRef = (Reference) i.next();
if (prevRef.getName().equals(ref.getName())
&& prevRef.getType().equals(ref.getType()))
// already handled.
return;
}
for (Iterator i = knownSubClasses.iterator(); i.hasNext(); )
((ClassIdentifier)i.next())
.reachableReference(ref, false);
virtualReachables.add(ref);
}
}
public void chainMethodIdentifier(Identifier chainIdent) {
String name = chainIdent.getName();
String typeSig = chainIdent.getType();
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (ident.getName().equals(name)
&& ident.getType().equals(typeSig))
chainIdent.addShadow(ident);
}
}
/**
* This is partly taken from the classpath project.
*/
public long calcSerialVersionUID() {
final MessageDigest md;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
GlobalOptions.err.println("Can't calculate serialVersionUID");
return 0L;
}
OutputStream digest = new OutputStream() {
public void write(int b) {
md.update((byte) b);
}
public void write(byte[] data, int offset, int length) {
md.update(data, offset, length);
}
};
DataOutputStream out = new DataOutputStream(digest);
try {
out.writeUTF(info.getName());
int modifiers = info.getModifiers();
// just look at interesting bits
modifiers = modifiers & ( Modifier.ABSTRACT | Modifier.FINAL
| Modifier.INTERFACE | Modifier.PUBLIC );
out.writeInt(modifiers);
ClassInfo[] interfaces
= (ClassInfo[]) info.getInterfaces().clone();
Arrays.sort(interfaces, new Comparator() {
public int compare( Object o1, Object o2 ) {
return ((ClassInfo)o1).getName()
.compareTo(((ClassInfo)o2).getName());
}
});
for( int i=0; i < interfaces.length; i++ ) {
out.writeUTF(interfaces[i].getName());
}
Comparator identCmp = new Comparator() {
public int compare(Object o1, Object o2) {
Identifier i1 = (Identifier)o1;
Identifier i2 = (Identifier)o2;
boolean special1 = (i1.equals("<init>")
|| i1.equals("<clinit>"));
boolean special2 = (i2.equals("<init>")
|| i2.equals("<clinit>"));
// Put constructors at the beginning
if (special1 != special2) {
return special1 ? -1 : 1;
}
int comp = i1.getName().compareTo(i2.getName());
if (comp != 0) {
return comp;
} else {
return i1.getType().compareTo(i2.getType());
}
}
};
List fields = Arrays.asList(fieldIdents.toArray());
List methods = Arrays.asList(methodIdents.toArray());
Collections.sort(fields, identCmp);
Collections.sort(methods, identCmp);
for (Iterator i = fields.iterator(); i.hasNext();) {
FieldIdentifier field = (FieldIdentifier) i.next();
modifiers = field.info.getModifiers();
if ((modifiers & Modifier.PRIVATE) != 0
&& (modifiers & (Modifier.STATIC
| Modifier.TRANSIENT)) != 0)
continue;
out.writeUTF(field.getName());
out.writeInt(modifiers);
out.writeUTF(field.getType());
}
for (Iterator i = methods.iterator(); i.hasNext(); ) {
MethodIdentifier method = (MethodIdentifier) i.next();
modifiers = method.info.getModifiers();
if( Modifier.isPrivate(modifiers))
continue;
out.writeUTF(method.getName());
out.writeInt(modifiers);
// the replacement of '/' with '.' was needed to make computed
// SUID's agree with those computed by JDK
out.writeUTF(method.getType().replace('/', '.'));
}
out.close();
byte[] sha = md.digest();
long result = 0;
for (int i=0; i < 8; i++) {
result += (long)(sha[i] & 0xFF) << (8 * i);
}
return result;
} catch (IOException ex) {
ex.printStackTrace();
GlobalOptions.err.println("Can't calculate serialVersionUID");
return 0L;
}
}
/**
* Preserve all fields, that are necessary, to serialize
* a compatible class.
*/
public void preserveSerializable() {
Identifier method
= findMethod("writeObject", "(Ljava.io.ObjectOutputStream)V");
if (method != null)
method.setPreserved();
method = findMethod("readObject", "(Ljava.io.ObjectInputStream)V");
if (method != null)
method.setPreserved();
if ((Main.options & Main.OPTION_PRESERVESERIAL) != 0) {
setPreserved();
Identifier UIDident = findField("serialVersionUID", "J");
if (UIDident == null) {
/* add a field serializableVersionUID if not existent */
long serialVersion = calcSerialVersionUID();
FieldInfo UIDField = new FieldInfo
(info, "serialVersionUID", "J",
Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
UIDField.setConstant(new Long(serialVersion));
UIDident = new FieldIdentifier(this, UIDField);
fieldIdents.add(UIDident);
}
UIDident.setReachable();
UIDident.setPreserved();
for (Iterator i=getFieldIdents().iterator(); i.hasNext(); ) {
FieldIdentifier ident = (FieldIdentifier) i.next();
if ((ident.info.getModifiers()
& (Modifier.TRANSIENT | Modifier.STATIC)) == 0) {
ident.setPreserved();
ident.setNotConstant();
}
/* XXX - only preserve them if writeObject not existent
* or if writeObject calls defaultWriteObject, and similar
* for readObject
*/
}
}
}
/**
* Marks the package as preserved, too.
*/
protected void setSinglePreserved() {
pack.setPreserved();
}
public void setSingleReachable() {
super.setSingleReachable();
Main.getClassBundle().analyzeIdentifier(this);
}
public void analyzeSuperClasses(ClassInfo superclass) {
while (superclass != null) {
if (superclass.getName().equals("java.io.Serializable"))
preserveSerializable();
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superclass.getName());
if (superident != null) {
superident.addSubClass(this);
} else {
// all virtual methods in superclass are reachable now!
String clazzType = ("L"+superclass.getName().replace('.', '/')
+";").intern();
MethodInfo[] topmethods = superclass.getMethods();
for (int i=0; i< topmethods.length; i++) {
int modif = topmethods[i].getModifiers();
if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
& modif) == 0
&& !topmethods[i].getName().equals("<init>")) {
reachableReference
(Reference.getReference(clazzType,
topmethods[i].getName(),
topmethods[i].getType()),
true);
}
}
}
ClassInfo[] ifaces = superclass.getInterfaces();
for (int i=0; i < ifaces.length; i++)
analyzeSuperClasses(ifaces[i]);
superclass = superclass.getSuperclass();
}
}
public void analyze() {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("Reachable: "+this);
ClassInfo[] ifaces = info.getInterfaces();
for (int i=0; i < ifaces.length; i++)
analyzeSuperClasses(ifaces[i]);
analyzeSuperClasses(info.getSuperclass());
}
public void initSuperClasses(ClassInfo superclass) {
while (superclass != null) {
if (superclass.getName().equals("java.lang.Serializable"))
preserveSerializable();
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superclass.getName());
if (superident != null) {
for (Iterator i = superident.getMethodIdents().iterator();
i.hasNext(); ) {
MethodIdentifier mid = (MethodIdentifier) i.next();
// all virtual methods in superclass must be chained.
int modif = mid.info.getModifiers();
if (((Modifier.PRIVATE
| Modifier.STATIC
| Modifier.FINAL) & modif) == 0
&& !(mid.getName().equals("<init>"))) {
// chain the preserved/same name lists.
chainMethodIdentifier(mid);
}
}
} else {
// all methods and fields in superclass are preserved!
MethodInfo[] topmethods = superclass.getMethods();
for (int i=0; i< topmethods.length; i++) {
// all virtual methods in superclass may be
// virtually reachable
int modif = topmethods[i].getModifiers();
if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
& modif) == 0
&& !topmethods[i].getName().equals("<init>")) {
Identifier method = findMethod
(topmethods[i].getName(), topmethods[i].getType());
if (method != null)
method.setPreserved();
}
}
}
ClassInfo[] ifaces = superclass.getInterfaces();
for (int i=0; i < ifaces.length; i++)
initSuperClasses(ifaces[i]);
superclass = superclass.getSuperclass();
}
}
public void initClass() {
info.loadInfo(info.FULLINFO);
FieldInfo[] finfos = info.getFields();
MethodInfo[] minfos = info.getMethods();
if (Main.swapOrder) {
Random rand = new Random();
Collections.shuffle(Arrays.asList(finfos), rand);
Collections.shuffle(Arrays.asList(minfos), rand);
}
fieldIdents = new ArrayList(finfos.length);
methodIdents = new ArrayList(minfos.length);
for (int i=0; i< finfos.length; i++)
fieldIdents.add(new FieldIdentifier(this, finfos[i]));
for (int i=0; i< minfos.length; i++) {
MethodIdentifier ident = new MethodIdentifier(this, minfos[i]);
methodIdents.add(ident);
if (ident.getName().equals("<clinit>")) {
/* If there is a static initializer, it is automatically
* reachable (even if this class wouldn't be otherwise).
*/
ident.setPreserved();
ident.setReachable();
} else if (ident.getName().equals("<init>"))
ident.setPreserved();
}
// preserve / chain inherited methods and fields.
ClassInfo[] ifaces = info.getInterfaces();
ifaceNames = new String[ifaces.length];
for (int i=0; i < ifaces.length; i++) {
ifaceNames[i] = ifaces[i].getName();
ClassIdentifier ifaceident = Main.getClassBundle()
.getClassIdentifier(ifaceNames[i]);
initSuperClasses(ifaces[i]);
}
if (info.getSuperclass() != null) {
superName = info.getSuperclass().getName();
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superName);
initSuperClasses(info.getSuperclass());
}
if ((Main.stripping & Main.STRIP_SOURCE) != 0) {
info.setSourceFile(null);
}
if ((Main.stripping & Main.STRIP_INNERINFO) != 0) {
info.setInnerClasses(new InnerClassInfo[0]);
info.setOuterClasses(new InnerClassInfo[0]);
info.setExtraClasses(new InnerClassInfo[0]);
}
// load inner classes
InnerClassInfo[] innerClasses = info.getInnerClasses();
InnerClassInfo[] outerClasses = info.getOuterClasses();
InnerClassInfo[] extraClasses = info.getExtraClasses();
if (outerClasses != null) {
for (int i=0; i < outerClasses.length; i++) {
if (outerClasses[i].outer != null) {
Main.getClassBundle()
.getClassIdentifier(outerClasses[i].outer);
}
}
}
if (innerClasses != null) {
for (int i=0; i < innerClasses.length; i++) {
Main.getClassBundle()
.getClassIdentifier(innerClasses[i].inner);
}
}
if (extraClasses != null) {
for (int i=0; i < extraClasses.length; i++) {
Main.getClassBundle()
.getClassIdentifier(extraClasses[i].inner);
if (extraClasses[i].outer != null)
Main.getClassBundle()
.getClassIdentifier(extraClasses[i].outer);
}
}
}
/**
* Add the ClassInfo objects of the interfaces of ancestor. But if
* an interface of ancestor is not reachable it will add its interfaces
* instead.
* @param result The Collection where the interfaces should be added to.
* @param ancestor The ancestor whose interfaces should be added.
*/
public void addIfaces(Collection result, ClassIdentifier ancestor) {
String[] ifaces = ancestor.ifaceNames;
ClassInfo[] ifaceInfos = ancestor.info.getInterfaces();
for (int i=0; i < ifaces.length; i++) {
ClassIdentifier ifaceident
= Main.getClassBundle().getClassIdentifier(ifaces[i]);
if (ifaceident != null && !ifaceident.isReachable())
addIfaces(result, ifaceident);
else
result.add(ifaceInfos[i]);
}
}
/**
* Generates the new super class and interfaces, removing super
* classes and interfaces that are not reachable.
* @return an array of class names (full qualified, dot separated)
* where the first entry is the super class (may be null) and the
* other entries are the interfaces.
*/
public void transformSuperIfaces() {
if ((Main.stripping & Main.STRIP_UNREACH) == 0)
return;
Collection newIfaces = new LinkedList();
ClassIdentifier ancestor = this;
while(true) {
addIfaces(newIfaces, ancestor);
ClassIdentifier superident
= Main.getClassBundle().getClassIdentifier(ancestor.superName);
if (superident == null || superident.isReachable())
break;
ancestor = superident;
}
ClassInfo superInfo = ancestor.info.getSuperclass();
ClassInfo[] ifaces = (ClassInfo[])
newIfaces.toArray(new ClassInfo[newIfaces.size()]);
info.setSuperclass(superInfo);
info.setInterfaces(ifaces);
}
public void transformInnerClasses() {
InnerClassInfo[] outerClasses = info.getOuterClasses();
if (outerClasses != null) {
int newOuterCount = outerClasses.length;
if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < outerClasses.length; i++) {
if (outerClasses[i].outer != null) {
ClassIdentifier outerIdent = Main.getClassBundle()
.getClassIdentifier(outerClasses[i].outer);
if (outerIdent != null && !outerIdent.isReachable())
newOuterCount--;
}
}
}
if (newOuterCount == 0) {
info.setOuterClasses(null);
} else {
InnerClassInfo[] newOuters = new InnerClassInfo[newOuterCount];
int pos = 0;
String lastClass = getFullAlias();
for (int i=0; i<outerClasses.length; i++) {
ClassIdentifier outerIdent = outerClasses[i].outer != null
? (Main.getClassBundle()
.getClassIdentifier(outerClasses[i].outer))
: null;
if (outerIdent != null && !outerIdent.isReachable())
continue;
String inner = lastClass;
String outer = outerIdent == null
? outerClasses[i].outer
: outerIdent.getFullAlias();
String name = outerClasses[i].name == null ? null
: ((outer != null && inner.startsWith(outer+"$"))
? inner.substring(outer.length()+1)
: inner.substring(inner.lastIndexOf('.')+1));
newOuters[pos++] = new InnerClassInfo
(inner, outer, name, outerClasses[i].modifiers);
lastClass = outer;
}
info.setOuterClasses(newOuters);
}
}
InnerClassInfo[] innerClasses = info.getInnerClasses();
if (innerClasses != null) {
int newInnerCount = innerClasses.length;
if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < innerClasses.length; i++) {
ClassIdentifier innerIdent = Main.getClassBundle()
.getClassIdentifier(innerClasses[i].inner);
if (innerIdent != null && !innerIdent.isReachable())
newInnerCount--;
}
}
if (newInnerCount == 0) {
info.setInnerClasses(null);
} else {
InnerClassInfo[] newInners = new InnerClassInfo[newInnerCount];
int pos = 0;
for (int i=0; i<innerClasses.length; i++) {
ClassIdentifier innerIdent = Main.getClassBundle()
.getClassIdentifier(innerClasses[i].inner);
if (innerIdent != null
&& (Main.stripping & Main.STRIP_UNREACH) != 0
&& !innerIdent.isReachable())
continue;
String inner = innerIdent == null
? innerClasses[i].inner
: innerIdent.getFullAlias();
String outer = getFullAlias();
String name = innerClasses[i].name == null ? null
: ((outer != null && inner.startsWith(outer+"$"))
? inner.substring(outer.length()+1)
: inner.substring(inner.lastIndexOf('.')+1));
newInners[pos++] = new InnerClassInfo
(inner, outer, name, innerClasses[i].modifiers);
}
info.setInnerClasses(newInners);
}
}
InnerClassInfo[] extraClasses = info.getExtraClasses();
if (extraClasses != null) {
int newExtraCount = extraClasses.length;
if ((Main.stripping & Main.STRIP_UNREACH) != 0) {
for (int i=0; i < extraClasses.length; i++) {
ClassIdentifier outerIdent = extraClasses[i].outer != null
? (Main.getClassBundle()
.getClassIdentifier(extraClasses[i].outer))
: null;
ClassIdentifier innerIdent = Main.getClassBundle()
.getClassIdentifier(extraClasses[i].inner);
if ((outerIdent != null && !outerIdent.isReachable())
|| (innerIdent != null && !innerIdent.isReachable()))
newExtraCount--;
}
}
if (newExtraCount == 0) {
info.setExtraClasses(null);
} else {
InnerClassInfo[] newExtras = newExtraCount > 0
? new InnerClassInfo[newExtraCount] : null;
int pos = 0;
for (int i=0; i<extraClasses.length; i++) {
ClassIdentifier outerIdent = extraClasses[i].outer != null
? (Main.getClassBundle()
.getClassIdentifier(extraClasses[i].outer))
: null;
ClassIdentifier innerIdent = Main.getClassBundle()
.getClassIdentifier(extraClasses[i].inner);
if (innerIdent != null && !innerIdent.isReachable())
continue;
if (outerIdent != null && !outerIdent.isReachable())
continue;
String inner = innerIdent == null
? extraClasses[i].inner
: innerIdent.getFullAlias();
String outer = outerIdent == null
? extraClasses[i].outer
: outerIdent.getFullAlias();
String name = extraClasses[i].name == null ? null
: ((outer != null && inner.startsWith(outer+"$"))
? inner.substring(outer.length()+1)
: inner.substring(inner.lastIndexOf('.')+1));
newExtras[pos++] = new InnerClassInfo
(inner, outer, name, extraClasses[i].modifiers);
}
info.setExtraClasses(newExtras);
}
}
}
public void doTransformations() {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("Transforming "+this);
info.setName(getFullAlias());
transformSuperIfaces();
transformInnerClasses();
Collection newFields = new ArrayList(fieldIdents.size());
Collection newMethods = new ArrayList(methodIdents.size());
for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) {
FieldIdentifier ident = (FieldIdentifier)i.next();
if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable()) {
ident.doTransformations();
newFields.add(ident.info);
}
}
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
MethodIdentifier ident = (MethodIdentifier)i.next();
if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable()) {
ident.doTransformations();
newMethods.add(ident.info);
}
}
info.setFields((FieldInfo[]) newFields.toArray
(new FieldInfo[newFields.size()]));
info.setMethods((MethodInfo[]) newMethods.toArray
(new MethodInfo[newMethods.size()]));
}
public void storeClass(DataOutputStream out) throws IOException {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("Writing "+this);
info.write(out);
info = null;
fieldIdents = methodIdents = null;
}
public Identifier getParent() {
return pack;
}
/**
* @return the full qualified name, excluding trailing dot.
*/
public String getFullName() {
return fullName;
}
/**
* @return the full qualified alias, excluding trailing dot.
*/
public String getFullAlias() {
if (pack.parent == null)
return getAlias();
else
return pack.getFullAlias() + "." + getAlias();
}
public String getName() {
return name;
}
public String getType() {
return "Ljava/lang/Class;";
}
public List getFieldIdents() {
return fieldIdents;
}
public List getMethodIdents() {
return methodIdents;
}
public Iterator getChilds() {
final Iterator fieldIter = fieldIdents.iterator();
final Iterator methodIter = methodIdents.iterator();
return new Iterator() {
boolean fieldsNext = fieldIter.hasNext();
public boolean hasNext() {
return fieldsNext ? true : methodIter.hasNext();
}
public Object next() {
if (fieldsNext) {
Object result = fieldIter.next();
fieldsNext = fieldIter.hasNext();
return result;
}
return methodIter.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public String toString() {
return "ClassIdentifier "+getFullName();
}
public Identifier getIdentifier(String fieldName, String typeSig) {
for (Iterator i = getChilds(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (ident.getName().equals(fieldName)
&& ident.getType().startsWith(typeSig))
return ident;
}
if (superName != null) {
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superName);
if (superident != null) {
Identifier ident
= superident.getIdentifier(fieldName, typeSig);
if (ident != null)
return ident;
}
}
return null;
}
public boolean containsFieldAliasDirectly(String fieldName, String typeSig,
ModifierMatcher matcher) {
for (Iterator i = fieldIdents.iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable())
&& ident.wasAliased()
&& ident.getAlias().equals(fieldName)
&& ident.getType().startsWith(typeSig)
&& matcher.matches(ident))
return true;
}
return false;
}
public boolean containsMethodAliasDirectly(String methodName,
String paramType,
ModifierMatcher matcher) {
for (Iterator i = methodIdents.iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable())
&& ident.wasAliased()
&& ident.getAlias().equals(methodName)
&& ident.getType().startsWith(paramType)
&& matcher.matches(ident))
return true;
}
return false;
}
public boolean fieldConflicts(FieldIdentifier field, String newAlias) {
String typeSig = (Main.options & Main.OPTION_STRONGOVERLOAD) != 0
? field.getType() : "";
/* Fields are similar to static methods: They are not
* overriden but hidden. We must only take care, that the
* reference of every getfield/putfield opcode points to the
* exact class, afterwards we can use doubled name as much as
* we want (event the decompiler can handle this). */
ModifierMatcher mm = ModifierMatcher.allowAll;
if (containsFieldAliasDirectly(newAlias, typeSig, mm))
return true;
return false;
}
public boolean methodConflicts(MethodIdentifier method, String newAlias) {
String paramType = method.getType();
if ((Main.options & Main.OPTION_STRONGOVERLOAD) == 0)
paramType = paramType.substring(0, paramType.indexOf(')')+1);
ModifierMatcher matcher = ModifierMatcher.allowAll;
if (containsMethodAliasDirectly(newAlias, paramType, matcher))
return true;
ModifierMatcher packMatcher = matcher.forceAccess(0, true);
if (method.info.isStatic()) {
/* A static method does not conflict with static methods
* in super classes or sub classes.
*/
packMatcher.forbidModifier(Modifier.STATIC);
}
/* We don't have to check interfaces: sub classes must always
* implement all methods in the interface (maybe abstract, but
* they must be there!).
*/
ClassInfo superInfo = info.getSuperclass();
ClassIdentifier superIdent = this;
while (superInfo != null) {
ClassIdentifier superident = Main.getClassBundle()
.getClassIdentifier(superInfo.getName());
if (superident != null) {
if (superident.containsMethodAliasDirectly
(newAlias, paramType, packMatcher))
return true;
} else {
MethodInfo[] minfos = superInfo.getMethods();
for (int i=0; i< minfos.length; i++) {
if (minfos[i].getName().equals(newAlias)
&& minfos[i].getType().startsWith(paramType)
&& packMatcher.matches(minfos[i].getModifiers()))
return true;
}
}
superInfo = superInfo.getSuperclass();
}
if (packMatcher.matches(method)) {
for (Iterator i = knownSubClasses.iterator(); i.hasNext(); ) {
ClassIdentifier ci = (ClassIdentifier) i.next();
if (ci.containsMethodAliasDirectly(newAlias, paramType,
packMatcher))
return true;
}
}
return false;
}
public boolean conflicting(String newAlias) {
return pack.contains(newAlias, this);
}
}

@ -1,25 +0,0 @@
/* CodeAnalyzer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.BytecodeInfo;
public interface CodeAnalyzer extends CodeTransformer {
public void analyzeCode(MethodIdentifier parent, BytecodeInfo bytecode);
}

@ -1,25 +0,0 @@
/* CodeTransformer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.BytecodeInfo;
public interface CodeTransformer {
public void transformCode(BytecodeInfo bytecode);
}

File diff suppressed because it is too large Load Diff

@ -1,311 +0,0 @@
/* ConstantRuntimeEnvironment Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.jvm.Interpreter;
import jode.jvm.SimpleRuntimeEnvironment;
import jode.jvm.InterpreterException;
import jode.bytecode.Reference;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.TypeSignature;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashSet;
public class ConstantRuntimeEnvironment extends SimpleRuntimeEnvironment {
/**
* The references that may be used in constant methods.
*/
static Set whiteList = new HashSet();
static void addWhite(Reference ref) {
whiteList.add(ref);
}
public static boolean isWhite(Reference ref) {
return whiteList.contains(ref);
}
public static boolean isWhite(String retTypeSig) {
return retTypeSig.length() == 1 // primitive type
|| whiteList.contains(retTypeSig);
}
static {
addWhite(Reference.getReference
("Ljava/lang/String;", "toCharArray", "()[C"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "<init>",
"(Ljava/lang/String;)V"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "<init>", "()V"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(Ljava/lang/String;)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(C)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(B)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(S)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(Z)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(F)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(I)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(J)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "append",
"(D)Ljava/lang/StringBuffer;"));
addWhite(Reference.getReference
("Ljava/lang/StringBuffer;", "toString",
"()Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "<init>", "()V"));
addWhite(Reference.getReference
("Ljava/lang/String;", "<init>", "([C)V"));
addWhite(Reference.getReference
("Ljava/lang/String;", "<init>", "([CII)V"));
addWhite(Reference.getReference
("Ljava/lang/String;", "<init>",
"(Ljava/lang/String;)V"));
addWhite(Reference.getReference
("Ljava/lang/String;", "<init>",
"(Ljava/lang/StringBuffer;)V"));
addWhite(Reference.getReference
("Ljava/lang/String;", "length", "()I"));
addWhite(Reference.getReference
("Ljava/lang/String;", "replace",
"(CC)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(Z)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(B)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(S)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(C)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(D)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(F)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(I)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(J)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "valueOf",
"(Ljava/lang/Object;)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "substring",
"(I)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/String;", "substring",
"(II)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava.lang/reflect/Modifier;", "toString",
"(I)Ljava/lang/String;"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "abs", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "abs", "(F)F"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "abs", "(I)I"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "abs", "(J)J"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "acos", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "asin", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "atan", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "atan2", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "ceil", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "cos", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "exp", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "floor", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "IEEEremainder", "(DD)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "log", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "max", "(DD)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "max", "(FF)F"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "max", "(II)I"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "max", "(JJ)J"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "min", "(DD)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "min", "(FF)F"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "min", "(II)I"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "min", "(JJ)J"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "pow", "(DD)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "rint", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "round", "(D)J"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "round", "(F)I"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "sin", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "sqrt", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "tan", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "toDegrees", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "toRadians", "(D)D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "E", "D"));
addWhite(Reference.getReference
("Ljava/lang/Math;", "PI", "D"));
whiteList.add("Ljava/lang/String;");
// whiteList.add("Ljava/lang/Class;");
// whiteList.add("Ljava/lang/reflect/Method;");
// whiteList.add("Ljava/lang/reflect/Field;");
}
private Interpreter interpreter;
public ConstantRuntimeEnvironment() {
interpreter = new Interpreter(this);
}
public static Object getDefaultValue(String typeSig) {
switch(typeSig.charAt(0)) {
case 'Z':
case 'B':
case 'S':
case 'C':
case 'I':
return new Integer(0);
case 'J':
return new Long(0L);
case 'D':
return new Double(0.0);
case 'F':
return new Float(0.0F);
default:
return null;
}
}
public Object getField(Reference ref, Object obj)
throws InterpreterException {
if (isWhite(ref))
return super.getField(ref, obj);
FieldIdentifier fi
= (FieldIdentifier) Main.getClassBundle().getIdentifier(ref);
if (fi != null && !fi.isNotConstant()) {
Object result = fi.getConstant();
if (result == null)
result = getDefaultValue(ref.getType());
return result;
}
throw new InterpreterException("Field " + ref + " not constant");
}
public void putField(Reference ref, Object obj, Object value)
throws InterpreterException {
throw new InterpreterException("Modifying Field " + ref + ".");
}
public Object invokeConstructor(Reference ref, Object[] params)
throws InterpreterException, InvocationTargetException {
if (isWhite(ref))
return super.invokeConstructor(ref, params);
throw new InterpreterException("Creating new Object " + ref + ".");
}
public Object invokeMethod(Reference ref, boolean isVirtual,
Object cls, Object[] params)
throws InterpreterException, InvocationTargetException {
if (isWhite(ref))
return super.invokeMethod(ref, isVirtual, cls, params);
MethodIdentifier mi
= (MethodIdentifier) Main.getClassBundle().getIdentifier(ref);
if (mi != null) {
BytecodeInfo code = mi.info.getBytecode();
if (code != null)
return interpreter.interpretMethod(code, cls, params);
}
throw new InterpreterException("Invoking library method " + ref + ".");
}
public boolean instanceOf(Object obj, String className)
throws InterpreterException {
Class clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
}
return obj != null && clazz.isInstance(obj);
}
public Object newArray(String type, int[] dimensions)
throws InterpreterException, NegativeArraySizeException {
if (type.length() == dimensions.length + 1) {
Class clazz;
try {
clazz = TypeSignature
.getClass(type.substring(dimensions.length));
} catch (ClassNotFoundException ex) {
throw new InterpreterException
("Class "+ex.getMessage()+" not found");
}
return Array.newInstance(clazz, dimensions);
}
throw new InterpreterException("Creating object array.");
}
}

@ -1,140 +0,0 @@
/* FieldIdentifier Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import java.lang.reflect.Modifier;
import jode.bytecode.*;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Collections;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.HashSet;
import @COLLECTIONS@.Map;
public class FieldIdentifier extends Identifier{
FieldInfo info;
ClassIdentifier clazz;
String name;
String type;
/**
* This field tells if the value is not constant. It is initially
* set to false, and if a write to that field is found, it is set
* to true.
*/
private boolean notConstant;
private Object constant;
/**
* The FieldChangeListener that should be notified if a
* write to this field is found.
*/
private Collection fieldListeners;
public FieldIdentifier(ClassIdentifier clazz, FieldInfo info) {
super(info.getName());
this.name = info.getName();
this.type = info.getType();
this.info = info;
this.clazz = clazz;
this.constant = info.getConstant();
}
public void setSingleReachable() {
super.setSingleReachable();
Main.getClassBundle().analyzeIdentifier(this);
}
public void analyze() {
String type = getType();
int index = type.indexOf('L');
if (index != -1) {
int end = type.indexOf(';', index);
Main.getClassBundle().reachableClass
(type.substring(index+1, end).replace('/', '.'));
}
}
public Identifier getParent() {
return clazz;
}
public String getFullName() {
return clazz.getFullName() + "." + getName() + "." + getType();
}
public String getFullAlias() {
return clazz.getFullAlias() + "." + getAlias() + "."
+ Main.getClassBundle().getTypeAlias(getType());
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public Iterator getChilds() {
return Collections.EMPTY_LIST.iterator();
}
public boolean isNotConstant() {
return notConstant;
}
public Object getConstant() {
return constant;
}
public void addFieldListener(Identifier ident) {
if (ident == null)
throw new NullPointerException();
if (fieldListeners == null)
fieldListeners = new HashSet();
if (!fieldListeners.contains(ident))
fieldListeners.add(ident);
}
public void setNotConstant() {
if (notConstant)
return;
notConstant = true;
if (fieldListeners == null)
return;
for (Iterator i = fieldListeners.iterator(); i.hasNext(); )
Main.getClassBundle().analyzeIdentifier((Identifier) i.next());
fieldListeners = null;
}
public String toString() {
return "FieldIdentifier "+getFullName();
}
public boolean conflicting(String newAlias) {
return clazz.fieldConflicts(this, newAlias);
}
public void doTransformations() {
info.setName(getAlias());
info.setType(Main.getClassBundle().getTypeAlias(type));
}
}

@ -1,248 +0,0 @@
/* Identifier Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.GlobalOptions;
import java.io.*;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.Iterator;
public abstract class Identifier {
/**
* This is a doubly list of identifiers, that must have always
* have the same names, and same preserved settings.
*/
private Identifier right = null;
private Identifier left = null;
private boolean reachable = false;
private boolean preserved = false;
private String alias = null;
private boolean wasAliased = false;
public Identifier(String alias) {
this.alias = alias;
}
/**
* Returns true, if this identifier is reachable in some way, false if it
* is dead and can be removed.
*/
public final boolean isReachable() {
return reachable;
}
/**
* true, if this identifier must preserve its name, false if the
* name may be obfuscated.
*/
public final boolean isPreserved() {
return preserved;
}
/**
* Marks this identifier as preserved. This will also make the
* identifier reachable, if it isn't already.
*
* You shouldn't call this directly, but use setPreserved instead.
*/
protected void setSinglePreserved() {
}
/**
* Marks this identifier as reachable.
*
* You should override this method for method identifier, which may
* mark other methods as reachable.
*
* You shouldn't call this directly, but use setReachable instead.
*/
protected void setSingleReachable() {
if (getParent() != null)
getParent().setReachable();
}
/**
* Mark all shadows as reachable.
*/
public void setReachable() {
if (!reachable) {
reachable = true;
setSingleReachable();
}
}
/**
* Mark all shadows as preserved.
*/
public void setPreserved() {
if (!preserved) {
preserved = true;
Identifier ptr = this;
while (ptr != null) {
ptr.setSinglePreserved();
ptr = ptr.left;
}
ptr = right;
while (ptr != null) {
ptr.setSinglePreserved();
ptr = ptr.right;
}
}
}
public Identifier getRepresentative() {
Identifier ptr = this;
while (ptr.left != null)
ptr = ptr.left;
return ptr;
}
public final boolean isRepresentative() {
return left == null;
}
public final boolean wasAliased() {
return getRepresentative().wasAliased;
}
public final void setAlias(String name) {
if (name != null) {
Identifier rep = getRepresentative();
rep.wasAliased = true;
rep.alias = name;
}
}
public final String getAlias() {
return getRepresentative().alias;
}
/**
* Mark that this identifier and the given identifier must always have
* the same name.
*/
public void addShadow(Identifier orig) {
if (isPreserved() && !orig.isPreserved())
orig.setPreserved();
else if (!isPreserved() && orig.isPreserved())
setPreserved();
Identifier ptr = this;
while (ptr.right != null)
ptr = ptr.right;
/* Check if orig is already on the ptr chain */
Identifier check = orig;
while (check.right != null)
check = check.right;
if (check == ptr)
return;
while (orig.left != null)
orig = orig.left;
ptr.right = orig;
orig.left = ptr;
}
static int serialnr = 0;
public void buildTable(Renamer renameRule) {
if (!isReachable()
&& (Main.stripping & Main.STRIP_UNREACH) != 0)
return;
if (isPreserved()) {
if (GlobalOptions.verboseLevel > 4)
GlobalOptions.err.println(toString() + " is preserved");
} else {
Identifier rep = getRepresentative();
if (rep.wasAliased)
return;
rep.wasAliased = true;
// set alias to empty string, so it won't conflict!
rep.alias = "";
Iterator aliases = renameRule.generateNames(this);
next_alias:
for (;;) {
String newAlias = (String) aliases.next();
Identifier ptr = rep;
while (ptr != null) {
if (ptr.conflicting(newAlias))
continue next_alias;
ptr = ptr.right;
}
setAlias(newAlias.toString());
break;
}
}
for (Iterator i = getChilds(); i.hasNext(); )
((Identifier)i.next()).buildTable(renameRule);
}
public void writeTable(Map table) {
if (!isReachable()
&& (Main.stripping & Main.STRIP_UNREACH) != 0)
return;
table.put(getFullAlias(), getName());
for (Iterator i = getChilds(); i.hasNext(); )
((Identifier)i.next()).writeTable(table);
}
public void readTable(Map table) {
Identifier rep = getRepresentative();
if (!rep.wasAliased) {
String newAlias = (String) table.get(getFullName());
if (newAlias != null) {
rep.wasAliased = true;
rep.setAlias(newAlias);
}
}
for (Iterator i = getChilds(); i.hasNext(); )
((Identifier)i.next()).readTable(table);
}
public void applyPreserveRule(IdentifierMatcher preserveRule) {
if (preserveRule.matches(this)) {
System.err.println("preserving: "+this);
setReachable();
setPreserved();
}
for (Iterator i = getChilds(); i.hasNext(); )
((Identifier)i.next()).applyPreserveRule(preserveRule);
}
public abstract Iterator getChilds();
public abstract Identifier getParent();
public abstract String getName();
public abstract String getType();
public abstract String getFullName();
public abstract String getFullAlias();
public abstract boolean conflicting(String newAlias);
/**
* This is called by ClassBundle when it a class is added with
* ClassBundle.analyzeIdentifier().
*/
public void analyze() {
}
}

@ -1,44 +0,0 @@
/* IdentifierMatcher Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
public interface IdentifierMatcher {
/**
* Returns true, if the ident is matched by this matcher.
*/
public boolean matches(Identifier ident);
/**
* Returns true, if there may be a sub ident, that is matched by
* this matcher.
* @param subIdent the name of the sub ident, or null if every
* name is okay.
*/
public boolean matchesSub(Identifier ident, String subIdent);
/**
* Returns the unique name of the single sub item, for which matches
* or matchesSub returns true.
* @return the unique name, or null, if there is not a unique sub
* item.
*/
public String getNextComponent(Identifier ident);
}

@ -1,62 +0,0 @@
/* LocalIdentifier Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Collections;
import @COLLECTIONS@.Iterator;
public class LocalIdentifier extends Identifier {
String name;
String type;
public LocalIdentifier(String name, String type, MethodIdentifier mIdent) {
super(name);
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public Iterator getChilds() {
return Collections.EMPTY_LIST.iterator();
}
public Identifier getParent() {
return null;
}
public String getFullName() {
return name;
}
public String getFullAlias() {
return getAlias();
}
public boolean conflicting(String newAlias) {
return false;
}
}

@ -1,940 +0,0 @@
/* LocalOptimizer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import java.util.*;
import jode.bytecode.*;
import jode.AssertError;
import jode.GlobalOptions;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/**
* This class takes some bytecode and tries to minimize the number
* of locals used. It will also remove unnecessary stores.
*
* This class can only work on verified code. There should also be no
* deadcode, since the verifier doesn't check that deadcode behaves
* okay.
*
* This is done in two phases. First we determine which locals are
* the same, and which locals have a overlapping life time. In the
* second phase we will then redistribute the locals with a coloring
* graph algorithm.
*
* The idea for the first phase is: For each read we follow the
* instruction flow backward to find the corresponding writes. We can
* also merge with another control flow that has a different read, in
* this case we merge with that read, too.
*
* The tricky part is the subroutine handling. We follow the local
* that is used in a ret and find the corresponding jsr target (there
* must be only one, if the verifier should accept this class). While
* we do this we remember in the info of the ret, which locals are
* used in that subroutine.
*
* When we know the jsr target<->ret correlation, we promote from the
* nextByAddr of every jsr the locals that are accessed by the
* subroutine to the corresponding ret and the others to the jsr. Also
* we will promote all reads from the jsr targets to the jsr.
*
* If you think this might be to complicated, keep in mind that jsr's
* are not only left by the ret instructions, but also "spontanously"
* (by not reading the return address again).
*/
public class LocalOptimizer implements Opcodes, CodeTransformer {
/**
* This class keeps track of which locals must be the same, which
* name and type each local (if there is a local variable table) and
* which other locals have an intersecting life time.
*/
class LocalInfo {
LocalInfo shadow = null;
public LocalInfo getReal() {
LocalInfo real = this;
while (real.shadow != null)
real = real.shadow;
return real;
}
String name;
String type;
Vector usingInstrs = new Vector();
Vector conflictingLocals = new Vector();
int size;
int newSlot = -1;
LocalInfo() {
}
LocalInfo(InstrInfo instr) {
usingInstrs.addElement(instr);
}
void conflictsWith(LocalInfo l) {
if (shadow != null) {
getReal().conflictsWith(l);
} else {
l = l.getReal();
if (!conflictingLocals.contains(l)) {
conflictingLocals.addElement(l);
l.conflictingLocals.addElement(this);
}
}
}
void combineInto(LocalInfo l) {
if (shadow != null) {
getReal().combineInto(l);
return;
}
l = l.getReal();
if (this == l)
return;
shadow = l;
if (shadow.name == null) {
shadow.name = name;
shadow.type = type;
}
Enumeration enum = usingInstrs.elements();
while (enum.hasMoreElements()) {
InstrInfo instr = (InstrInfo) enum.nextElement();
instr.local = l;
l.usingInstrs.addElement(instr);
}
}
public int getFirstAddr() {
int minAddr = Integer.MAX_VALUE;
Enumeration enum = usingInstrs.elements();
while (enum.hasMoreElements()) {
InstrInfo info = (InstrInfo) enum.nextElement();
if (info.instr.getAddr() < minAddr)
minAddr = info.instr.getAddr();
}
return minAddr;
}
}
private static class TodoQueue {
public final InstrInfo LAST = new InstrInfo();
InstrInfo first = LAST;
public void add(InstrInfo info) {
if (info.nextTodo == null) {
/* only enqueue if not already on queue */
info.nextTodo = first;
first = info;
}
}
public boolean isEmpty() {
return first == LAST;
}
public InstrInfo remove() {
if (first == LAST)
throw new NoSuchElementException();
InstrInfo result = first;
first = result.nextTodo;
result.nextTodo = null;
return result;
}
}
/**
* This class contains information for each instruction.
*/
static class InstrInfo {
/**
* The next changed InstrInfo, or null, if this instr info did
* not changed.
*/
InstrInfo nextTodo;
/**
* The LocalInfo that this instruction manipulates, or null
* if this is not an ret, iinc, load or store instruction.
*/
LocalInfo local;
/**
* For each slot, this contains the InstrInfo of one of the
* next Instruction, that may read from that slot, without
* prior writing. */
InstrInfo[] nextReads;
/**
* This only has a value for ret instructions. In that case
* this bitset contains all locals, that may be used between
* jsr and ret.
*/
BitSet usedBySub;
/**
* For each slot if get() is true, no instruction may read
* this slot, since it may contain different locals, depending
* on flow.
*/
LocalInfo[] lifeLocals;
/**
* If instruction is the destination of a jsr, this contains
* the single allowed ret instruction info, or null if there
* is no ret at all (or not yet detected).
*/
InstrInfo retInfo;
/**
* If this instruction is a ret, this contains the single
* allowed jsr target to which this ret belongs.
*/
InstrInfo jsrTargetInfo;
/**
* The Instruction of this info
*/
Instruction instr;
/**
* The next info in the chain.
*/
InstrInfo nextInfo;
}
BytecodeInfo bc;
TodoQueue changedInfos;
InstrInfo firstInfo;
Hashtable instrInfos;
boolean produceLVT;
int maxlocals;
LocalInfo[] paramLocals;
public LocalOptimizer() {
}
/**
* Merges the given vector to a new vector. Both vectors may
* be null in which case they are interpreted as empty vectors.
* The vectors will never changed, but the result may be one
* of the given vectors.
*/
Vector merge(Vector v1, Vector v2) {
if (v1 == null || v1.isEmpty())
return v2;
if (v2 == null || v2.isEmpty())
return v1;
Vector result = (Vector) v1.clone();
Enumeration enum = v2.elements();
while (enum.hasMoreElements()) {
Object elem = enum.nextElement();
if (!result.contains(elem))
result.addElement(elem);
}
return result;
}
void promoteReads(InstrInfo info, Instruction preInstr,
BitSet mergeSet, boolean inverted) {
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr);
int omitLocal = -1;
if (preInstr.getOpcode() >= opc_istore
&& preInstr.getOpcode() <= opc_astore) {
/* This is a store */
omitLocal = preInstr.getLocalSlot();
if (info.nextReads[omitLocal] != null)
preInfo.local.combineInto(info.nextReads[omitLocal].local);
}
for (int i=0; i < maxlocals; i++) {
if (info.nextReads[i] != null && i != omitLocal
&& (mergeSet == null || mergeSet.get(i) != inverted)) {
if (preInfo.nextReads[i] == null) {
preInfo.nextReads[i] = info.nextReads[i];
changedInfos.add(preInfo);
} else {
preInfo.nextReads[i].local
.combineInto(info.nextReads[i].local);
}
}
}
}
void promoteReads(InstrInfo info, Instruction preInstr) {
promoteReads(info, preInstr, null, false);
}
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
int slot, int addr) {
LocalVariableInfo match = null;
for (int i=0; i < lvt.length; i++) {
if (lvt[i].slot == slot
&& lvt[i].start.getAddr() <= addr
&& lvt[i].end.getAddr() >= addr) {
if (match != null
&& (!match.name.equals(lvt[i].name)
|| !match.type.equals(lvt[i].type))) {
/* Multiple matches..., give no info */
return null;
}
match = lvt[i];
}
}
return match;
}
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
Instruction instr) {
int addr;
if (instr.getOpcode() >= opc_istore
&& instr.getOpcode() <= opc_astore)
addr = instr.getNextAddr();
else
addr = instr.getAddr();
return findLVTEntry(lvt, instr.getLocalSlot(), addr);
}
public void calcLocalInfo() {
maxlocals = bc.getMaxLocals();
Handler[] handlers = bc.getExceptionHandlers();
LocalVariableInfo[] lvt = bc.getLocalVariableTable();
if (lvt != null)
produceLVT = true;
/* Initialize paramLocals */
{
String methodType = bc.getMethodInfo().getType();
int paramCount = (bc.getMethodInfo().isStatic() ? 0 : 1)
+ TypeSignature.getArgumentSize(methodType);
paramLocals = new LocalInfo[paramCount];
int slot = 0;
if (!bc.getMethodInfo().isStatic()) {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, 0, 0);
if (lvi != null) {
local.name = lvi.name;
local.type = lvi.type;
}
}
local.size = 1;
paramLocals[slot++] = local;
}
int pos = 1;
while (pos < methodType.length()
&& methodType.charAt(pos) != ')') {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0);
if (lvi != null) {
local.name = lvi.name;
}
}
int start = pos;
pos = TypeSignature.skipType(methodType, pos);
local.type = methodType.substring(start, pos);
local.size = TypeSignature.getTypeSize(local.type);
paramLocals[slot] = local;
slot += local.size;
}
}
/* Initialize the InstrInfos and LocalInfos
*/
changedInfos = new TodoQueue();
instrInfos = new Hashtable();
{
InstrInfo info = firstInfo = new InstrInfo();
Iterator i = bc.getInstructions().iterator();
while (true) {
Instruction instr = (Instruction) i.next();
instrInfos.put(instr, info);
info.instr = instr;
info.nextReads = new InstrInfo[maxlocals];
if (instr.hasLocalSlot()) {
info.local = new LocalInfo(info);
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, instr);
if (lvi != null) {
info.local.name = lvi.name;
info.local.type = lvi.type;
}
}
info.local.size = 1;
switch (instr.getOpcode()) {
case opc_lload: case opc_dload:
info.local.size = 2;
/* fall through */
case opc_iload: case opc_fload: case opc_aload:
case opc_iinc:
/* this is a load instruction */
info.nextReads[instr.getLocalSlot()] = info;
changedInfos.add(info);
break;
case opc_ret:
/* this is a ret instruction */
info.usedBySub = new BitSet();
info.nextReads[instr.getLocalSlot()] = info;
changedInfos.add(info);
break;
case opc_lstore: case opc_dstore:
info.local.size = 2;
//case opc_istore: case opc_fstore: case opc_astore:
}
}
if (!i.hasNext())
break;
info = info.nextInfo = new InstrInfo();
}
}
/* find out which locals are the same.
*/
while (!changedInfos.isEmpty()) {
InstrInfo info = changedInfos.remove();
Instruction instr = info.instr;
/* Mark the local as used in all ret instructions */
if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
for (int i=0; i< maxlocals; i++) {
InstrInfo retInfo = info.nextReads[i];
if (retInfo != null
&& retInfo.instr.getOpcode() == opc_ret
&& !retInfo.usedBySub.get(slot)) {
retInfo.usedBySub.set(slot);
if (retInfo.jsrTargetInfo != null)
changedInfos.add(retInfo.jsrTargetInfo);
}
}
}
Instruction prevInstr = instr.getPrevByAddr();
if (prevInstr != null) {
if (!prevInstr.doesAlwaysJump())
promoteReads(info, prevInstr);
else if (prevInstr.getOpcode() == opc_jsr) {
/* Prev instr is a jsr, promote reads to the
* corresponding ret.
*/
InstrInfo jsrInfo =
(InstrInfo) instrInfos.get(prevInstr.getSingleSucc());
if (jsrInfo.retInfo != null) {
/* Now promote reads that are modified by the
* subroutine to the ret, and those that are not
* to the jsr instruction.
*/
promoteReads(info, jsrInfo.retInfo.instr,
jsrInfo.retInfo.usedBySub, false);
promoteReads(info, prevInstr,
jsrInfo.retInfo.usedBySub, true);
}
}
}
if (instr.getPreds() != null) {
for (int i = 0; i < instr.getPreds().length; i++) {
Instruction predInstr = instr.getPreds()[i];
if (instr.getPreds()[i].getOpcode() == opc_jsr) {
/* This is the target of a jsr instr.
*/
if (info.instr.getOpcode() != opc_astore) {
/* XXX Grrr, the bytecode verifier doesn't
* test if a jsr starts with astore. So
* it is possible to do something else
* before putting the ret address into a
* local. */
throw new AssertError("Non standard jsr");
}
InstrInfo retInfo = info.nextInfo.nextReads
[info.instr.getLocalSlot()];
if (retInfo != null) {
if (retInfo.instr.getOpcode() != opc_ret)
throw new AssertError
("reading return address");
info.retInfo = retInfo;
retInfo.jsrTargetInfo = info;
/* Now promote reads from the instruction
* after the jsr to the ret instruction if
* they are modified by the subroutine,
* and to the jsr instruction otherwise.
*/
Instruction nextInstr = predInstr.getNextByAddr();
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(nextInstr);
promoteReads(nextInfo, retInfo.instr,
retInfo.usedBySub, false);
promoteReads(nextInfo, predInstr,
retInfo.usedBySub, true);
}
}
promoteReads(info, instr.getPreds()[i]);
}
}
for (int i=0; i < handlers.length; i++) {
if (handlers[i].catcher == instr) {
for (Instruction preInstr = handlers[i].start;
preInstr != handlers[i].end.getNextByAddr();
preInstr = preInstr.getNextByAddr()) {
promoteReads(info, preInstr);
}
}
}
}
changedInfos = null;
/* Now merge with the parameters
* The params should be the locals in firstInfo.nextReads
*/
for (int i=0; i< paramLocals.length; i++) {
if (firstInfo.nextReads[i] != null) {
firstInfo.nextReads[i].local.combineInto(paramLocals[i]);
paramLocals[i] = paramLocals[i].getReal();
}
}
}
public void stripLocals() {
ListIterator iter = bc.getInstructions().listIterator();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
Instruction instr = (Instruction) iter.next();
if (info.local != null && info.local.usingInstrs.size() == 1) {
/* If this is a store, whose value is never read; it can
* be removed, i.e replaced by a pop. */
switch (instr.getOpcode()) {
case opc_istore:
case opc_fstore:
case opc_astore:
iter.set(new Instruction(opc_pop));
break;
case opc_lstore:
case opc_dstore:
iter.set(new Instruction(opc_pop2));
break;
default:
}
}
}
}
void distributeLocals(Vector locals) {
if (locals.size() == 0)
return;
/* Find the local with the least conflicts. */
int min = Integer.MAX_VALUE;
LocalInfo bestLocal = null;
Enumeration enum = locals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
int conflicts = 0;
Enumeration conflenum = li.conflictingLocals.elements();
while (conflenum.hasMoreElements()) {
if (((LocalInfo)conflenum.nextElement()).newSlot != -2)
conflicts++;
}
if (conflicts < min) {
min = conflicts;
bestLocal = li;
}
}
/* Mark the local as taken */
locals.removeElement(bestLocal);
bestLocal.newSlot = -2;
/* Now distribute the remaining locals recursively. */
distributeLocals(locals);
/* Finally find a new slot */
next_slot:
for (int slot = 0; ; slot++) {
Enumeration conflenum = bestLocal.conflictingLocals.elements();
while (conflenum.hasMoreElements()) {
LocalInfo conflLocal = (LocalInfo)conflenum.nextElement();
if (bestLocal.size == 2 && conflLocal.newSlot == slot+1) {
slot++;
continue next_slot;
}
if (conflLocal.size == 2 && conflLocal.newSlot+1 == slot)
continue next_slot;
if (conflLocal.newSlot == slot) {
if (conflLocal.size == 2)
slot++;
continue next_slot;
}
}
bestLocal.newSlot = slot;
break;
}
}
public void distributeLocals() {
/* give locals new slots. This is a graph coloring
* algorithm (the optimal solution is NP complete, but this
* should be a good approximation).
*/
/* first give the params the same slot as they had before.
*/
for (int i=0; i<paramLocals.length; i++)
if (paramLocals[i] != null)
paramLocals[i].newSlot = i;
/* Now calculate the conflict settings.
*/
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.instr.getOpcode() >= BytecodeInfo.opc_istore
&& info.instr.getOpcode() <= BytecodeInfo.opc_astore) {
/* This is a store. It conflicts with every local, whose
* value will be read without write.
*
* If this is inside a ret, it also conflicts with
* locals, that are not used inside, and where any jsr
* would conflict with.
*/
for (int i=0; i < maxlocals; i++) {
if (i != info.instr.getLocalSlot()
&& info.nextReads[i] != null)
info.local.conflictsWith(info.nextReads[i].local);
if (info.nextInfo.nextReads[i] != null
&& info.nextInfo.nextReads[i].jsrTargetInfo != null) {
Instruction[] jsrs = info.nextInfo.nextReads[i]
.jsrTargetInfo.instr.getPreds();
for (int j=0; j< jsrs.length; j++) {
InstrInfo jsrInfo
= (InstrInfo) instrInfos.get(jsrs[j]);
for (int k=0; k < maxlocals; k++) {
if (!info.nextInfo.nextReads[i].usedBySub
.get(k)
&& jsrInfo.nextReads[k] != null)
info.local.conflictsWith
(jsrInfo.nextReads[k].local);
}
}
}
}
}
}
/* Now put the locals that need a color into a vector.
*/
Vector locals = new Vector();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null
&& info.local.newSlot == -1
&& !locals.contains(info.local))
locals.addElement(info.local);
}
/* Now distribute slots recursive.
*/
distributeLocals(locals);
/* Update the instructions and calculate new maxlocals.
*/
maxlocals = paramLocals.length;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) {
if (info.local.newSlot+info.local.size > maxlocals)
maxlocals = info.local.newSlot + info.local.size;
info.instr.setLocalSlot(info.local.newSlot);
}
}
bc.setMaxLocals(maxlocals);
/* Update LocalVariableTable
*/
if (produceLVT)
buildNewLVT();
}
private InstrInfo CONFLICT = new InstrInfo();
boolean promoteLifeLocals(LocalInfo[] newLife, InstrInfo nextInfo) {
if (nextInfo.lifeLocals == null) {
nextInfo.lifeLocals = (LocalInfo[]) newLife.clone();
return true;
}
boolean changed = false;
for (int i=0; i< maxlocals; i++) {
LocalInfo local = nextInfo.lifeLocals[i];
if (local == null)
/* A conflict has already happened, or this slot
* may not have been initialized. */
continue;
local = local.getReal();
LocalInfo newLocal = newLife[i];
if (newLocal != null)
newLocal = newLocal.getReal();
if (local != newLocal) {
nextInfo.lifeLocals[i] = null;
changed = true;
}
}
return changed;
}
public void buildNewLVT() {
/* First we recalculate the usedBySub, to use the new local numbers.
*/
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo)
if (info.usedBySub != null)
info.usedBySub = new BitSet();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) {
for (int i=0; i < info.nextReads.length; i++) {
if (info.nextReads[i] != null
&& info.nextReads[i].instr.getOpcode() == opc_ret)
info.nextReads[i].usedBySub.set(info.local.newSlot);
}
}
}
/* Now we begin with the first Instruction and follow program flow.
* We remember which locals are life in lifeLocals.
*/
firstInfo.lifeLocals = new LocalInfo[maxlocals];
for (int i=0; i < paramLocals.length; i++)
firstInfo.lifeLocals[i] = paramLocals[i];
Stack changedInfo = new Stack();
changedInfo.push(firstInfo);
Handler[] handlers = bc.getExceptionHandlers();
while (!changedInfo.isEmpty()) {
InstrInfo info = (InstrInfo) changedInfo.pop();
Instruction instr = info.instr;
LocalInfo[] newLife = info.lifeLocals;
if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
LocalInfo instrLocal = info.local.getReal();
newLife = (LocalInfo[]) newLife.clone();
newLife[slot] = instrLocal;
if (instrLocal.name != null) {
for (int j=0; j< newLife.length; j++) {
if (j != slot
&& newLife[j] != null
&& instrLocal.name.equals(newLife[j].name)) {
/* This local changed the slot. */
newLife[j] = null;
}
}
}
}
if (!instr.doesAlwaysJump()) {
InstrInfo nextInfo = info.nextInfo;
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
if (instr.hasSuccs()) {
Instruction[] succs = instr.getSuccs();
for (int i = 0; i < succs.length; i++) {
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(succs[i]);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
}
for (int i=0; i < handlers.length; i++) {
if (handlers[i].start.compareTo(instr) <= 0
&& handlers[i].end.compareTo(instr) >= 0) {
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(handlers[i].catcher);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
}
if (info.instr.getOpcode() == opc_jsr) {
/* On a jsr we do a special merge */
Instruction jsrTargetInstr = info.instr.getSingleSucc();
InstrInfo jsrTargetInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr);
InstrInfo retInfo = jsrTargetInfo.retInfo;
if (retInfo != null && retInfo.lifeLocals != null) {
LocalInfo[] retLife = (LocalInfo[]) newLife.clone();
for (int i=0; i< maxlocals; i++) {
if (retInfo.usedBySub.get(i))
retLife[i] = retInfo.lifeLocals[i];
}
if (promoteLifeLocals(retLife, info.nextInfo))
changedInfo.push(info.nextInfo);
}
}
if (info.jsrTargetInfo != null) {
/* On a ret we do a special merge */
Instruction jsrTargetInstr = info.jsrTargetInfo.instr;
for (int j=0; j< jsrTargetInstr.getPreds().length; j++) {
InstrInfo jsrInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr.getPreds()[j]);
if (jsrInfo.lifeLocals == null)
/* life locals are not calculated, yet */
continue;
LocalInfo[] retLife = (LocalInfo[]) newLife.clone();
for (int i=0; i< maxlocals; i++) {
if (!info.usedBySub.get(i))
retLife[i] = jsrInfo.lifeLocals[i];
}
if (promoteLifeLocals(retLife, jsrInfo.nextInfo))
changedInfo.push(jsrInfo.nextInfo);
}
}
}
Vector lvtEntries = new Vector();
LocalVariableInfo[] lvi = new LocalVariableInfo[maxlocals];
LocalInfo[] currentLocal = new LocalInfo[maxlocals];
for (int i=0; i< paramLocals.length; i++) {
if (paramLocals[i] != null) {
currentLocal[i] = paramLocals[i];
if (currentLocal[i].name != null) {
lvi[i] = new LocalVariableInfo();
lvtEntries.addElement(lvi[i]);
lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */
lvi[i].type = Main.getClassBundle()
.getTypeAlias(currentLocal[i].type);
lvi[i].start = (Instruction) bc.getInstructions().get(0);
lvi[i].slot = i;
}
}
}
Instruction lastInstr = null;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
for (int i=0; i< maxlocals; i++) {
LocalInfo lcl = info.lifeLocals != null ? info.lifeLocals[i]
: null;
if (lcl != currentLocal[i]
&& (lcl == null || currentLocal[i] == null
|| lcl.name == null || lcl.type == null
|| !lcl.name.equals(currentLocal[i].name)
|| !lcl.type.equals(currentLocal[i].type))) {
if (lvi[i] != null) {
lvi[i].end = info.instr.getPrevByAddr();
}
lvi[i] = null;
currentLocal[i] = lcl;
if (currentLocal[i] != null
&& currentLocal[i].name != null
&& currentLocal[i].type != null) {
lvi[i] = new LocalVariableInfo();
lvtEntries.addElement(lvi[i]);
lvi[i].name = currentLocal[i].name;
lvi[i].type = Main.getClassBundle()
.getTypeAlias(currentLocal[i].type);
lvi[i].start = info.instr;
lvi[i].slot = i;
}
}
}
lastInstr = info.instr;
}
for (int i=0; i< maxlocals; i++) {
if (lvi[i] != null)
lvi[i].end = lastInstr;
}
LocalVariableInfo[] lvt = new LocalVariableInfo[lvtEntries.size()];
lvtEntries.copyInto(lvt);
bc.setLocalVariableTable(lvt);
}
public void dumpLocals() {
Vector locals = new Vector();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
GlobalOptions.err.println(info.instr.getDescription());
GlobalOptions.err.print("nextReads: ");
for (int i=0; i<maxlocals; i++)
if (info.nextReads[i] == null)
GlobalOptions.err.print("-,");
else
GlobalOptions.err.print(info.nextReads[i].instr.getAddr()+",");
if (info.usedBySub != null)
GlobalOptions.err.print(" usedBySub: "+info.usedBySub);
if (info.retInfo != null)
GlobalOptions.err.print(" ret info: "
+info.retInfo.instr.getAddr());
if (info.jsrTargetInfo != null)
GlobalOptions.err.print(" jsr info: "
+info.jsrTargetInfo.instr.getAddr());
GlobalOptions.err.println();
if (info.local != null && !locals.contains(info.local))
locals.addElement(info.local);
}
Enumeration enum = locals.elements();
while (enum.hasMoreElements()) {
LocalInfo li = (LocalInfo) enum.nextElement();
int slot = ((InstrInfo)li.usingInstrs.elementAt(0))
.instr.getLocalSlot();
GlobalOptions.err.print("Slot: "+slot+" conflicts:");
Enumeration enum1 = li.conflictingLocals.elements();
while (enum1.hasMoreElements()) {
LocalInfo cfl = (LocalInfo)enum1.nextElement();
GlobalOptions.err.print(cfl.getFirstAddr()+", ");
}
GlobalOptions.err.println();
GlobalOptions.err.print(li.getFirstAddr());
GlobalOptions.err.print(" instrs: ");
Enumeration enum2 = li.usingInstrs.elements();
while (enum2.hasMoreElements())
GlobalOptions.err.print(((InstrInfo)enum2.nextElement())
.instr.getAddr()+", ");
GlobalOptions.err.println();
}
GlobalOptions.err.println("-----------");
}
public void transformCode(BytecodeInfo bytecode) {
this.bc = bytecode;
calcLocalInfo();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_LOCALS) != 0) {
GlobalOptions.err.println("Before Local Optimization: ");
dumpLocals();
}
stripLocals();
distributeLocals();
if ((GlobalOptions.debuggingFlags
& GlobalOptions.DEBUG_LOCALS) != 0) {
GlobalOptions.err.println("After Local Optimization: ");
dumpLocals();
}
firstInfo = null;
changedInfos = null;
instrInfos = null;
paramLocals = null;
}
}

@ -1,34 +0,0 @@
/* LocalizeFieldTransformer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
/**
* This class replaces accesses to local fields and .
*
*/
public class LocalizeFieldTransformer implements CodeTransformer {
public static void transformCode(BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
}
}
}

@ -1,183 +0,0 @@
/* Main Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import jode.GlobalOptions;
import gnu.getopt.LongOpt;
import gnu.getopt.Getopt;
import java.lang.reflect.Modifier;
import java.io.PrintWriter;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.IOException;
import @COLLECTIONS@.Collections;
public class Main {
public static boolean swapOrder = false;
public static final int OPTION_STRONGOVERLOAD = 0x0001;
public static final int OPTION_PRESERVESERIAL = 0x0002;
public static int options = OPTION_PRESERVESERIAL;
private static final LongOpt[] longOptions = new LongOpt[] {
new LongOpt("cp", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
new LongOpt("classpath", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
new LongOpt("destpath", LongOpt.REQUIRED_ARGUMENT, null, 'd'),
new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'V'),
new LongOpt("verbose", LongOpt.OPTIONAL_ARGUMENT, null, 'v'),
new LongOpt("debug", LongOpt.OPTIONAL_ARGUMENT, null, 'D'),
};
public static final String[] stripNames = {
"unreach", "inner", "lvt", "lnt", "source"
};
public static final int STRIP_UNREACH = 0x0001;
public static final int STRIP_INNERINFO = 0x0002;
public static final int STRIP_LVT = 0x0004;
public static final int STRIP_LNT = 0x0008;
public static final int STRIP_SOURCE = 0x0010;
public static int stripping = 0x1;
private static ClassBundle bundle;
public static void usage() {
PrintWriter err = GlobalOptions.err;
err.println("usage: jode.Obfuscator flags* script");
err.println(" -h, --help "+
"show this information.");
err.println(" -V, --version "+
"output version information and exit.");
err.println(" -v, --verbose "+
"be verbose (multiple times means more verbose).");
err.println(" -c, --classpath <path> "+
"search for classes in specified classpath.");
err.println(" "+
"The directories should be separated by ','.");
err.println(" -d, --dest <dir> "+
"write decompiled files to disk into directory destdir.");
err.println(" -D, --debug=... "+
"use --debug=help for more information.");
}
public static ClassBundle getClassBundle() {
return bundle;
}
public static void main(String[] params) {
if (params.length == 0) {
usage();
return;
}
String cp = null, dest = null;
GlobalOptions.err.println(GlobalOptions.copyright);
bundle = new ClassBundle();
boolean errorInParams = false;
Getopt g = new Getopt("jode.obfuscator.Main", params, "hVvc:d:D:",
longOptions, true);
for (int opt = g.getopt(); opt != -1; opt = g.getopt()) {
switch(opt) {
case 0:
break;
case 'h':
usage();
errorInParams = true;
break;
case 'V':
GlobalOptions.err.println(GlobalOptions.version);
break;
case 'c':
cp = g.getOptarg();
break;
case 'd':
dest = g.getOptarg();
break;
case 'v': {
String arg = g.getOptarg();
if (arg == null)
GlobalOptions.verboseLevel++;
else {
try {
GlobalOptions.verboseLevel = Integer.parseInt(arg);
} catch (NumberFormatException ex) {
GlobalOptions.err.println
("jode.Decompiler: Argument `"
+arg+"' to --verbose must be numeric:");
errorInParams = true;
}
}
break;
}
case 'D': {
String arg = g.getOptarg();
if (arg == null)
arg = "help";
errorInParams |= !GlobalOptions.setDebugging(arg);
break;
}
default:
errorInParams = true;
break;
}
}
if (errorInParams)
return;
if (g.getOptind() != params.length - 1) {
GlobalOptions.err.println("You must specify exactly one script.");
return;
}
try {
String filename = params[g.getOptind()];
ScriptParser parser = new ScriptParser
(filename.equals("-")
? new InputStreamReader(System.in)
: new FileReader(filename));
parser.parseOptions(bundle);
} catch (IOException ex) {
GlobalOptions.err.println
("IOException while reading script file.");
ex.printStackTrace(GlobalOptions.err);
return;
} catch (ParseException ex) {
GlobalOptions.err.println("Syntax error in script file: ");
GlobalOptions.err.println(ex.getMessage());
if (GlobalOptions.verboseLevel > 5)
ex.printStackTrace(GlobalOptions.err);
return;
}
// Command Line overwrites script options:
if (cp != null)
bundle.setOption("classpath", Collections.singleton(cp));
if (dest != null)
bundle.setOption("dest", Collections.singleton(dest));
bundle.run();
}
}

@ -1,55 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir)
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \
ClassBundle.java \
ClassIdentifier.java \
CodeAnalyzer.java \
CodeTransformer.java \
ConstantAnalyzer.java \
ConstantRuntimeEnvironment.java \
FieldIdentifier.java \
Identifier.java \
IdentifierMatcher.java \
LocalIdentifier.java \
LocalOptimizer.java \
Main.java \
MethodIdentifier.java \
ModifierMatcher.java \
MultiIdentifierMatcher.java \
NameSwapper.java \
OptionHandler.java \
PackageIdentifier.java \
ParseException.java \
RemovePopAnalyzer.java \
Renamer.java \
ScriptParser.java \
SimpleAnalyzer.java \
StrongRenamer.java \
TranslationTable.java \
UniqueRenamer.java \
WildCard.java
# LocalizeFieldTransformer.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include $(MY_JAVA_FILES:.java=.dep)
%.class: %.java
$(JAVAC) -classpath `$(SUBSTCP) $(BUILD_CLASSPATH):$(CLASSLIB)` -d $(top_builddir) $<
%.dep: %.class
$(JAVADEP) $< >$@
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,235 +0,0 @@
/* MethodIdentifier Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.AssertError;
import jode.GlobalOptions;
import jode.bytecode.*;
import @COLLECTIONS@.Collections;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.Map;
import java.lang.reflect.Modifier;
import java.util.BitSet;
public class MethodIdentifier extends Identifier implements Opcodes {
ClassIdentifier clazz;
MethodInfo info;
String name;
String type;
boolean globalSideEffects;
BitSet localSideEffects;
/**
* The code analyzer of this method, or null if there isn't any.
*/
CodeAnalyzer codeAnalyzer;
public MethodIdentifier(ClassIdentifier clazz, MethodInfo info) {
super(info.getName());
this.name = info.getName();
this.type = info.getType();
this.clazz = clazz;
this.info = info;
BytecodeInfo bytecode = info.getBytecode();
if (bytecode != null) {
if ((Main.stripping & Main.STRIP_LVT) != 0)
info.getBytecode().setLocalVariableTable(null);
if ((Main.stripping & Main.STRIP_LNT) != 0)
info.getBytecode().setLineNumberTable(null);
codeAnalyzer = Main.getClassBundle().getCodeAnalyzer();
CodeTransformer[] trafos
= Main.getClassBundle().getPreTransformers();
for (int i = 0; i < trafos.length; i++) {
trafos[i].transformCode(bytecode);
}
info.setBytecode(bytecode);
}
}
public Iterator getChilds() {
return Collections.EMPTY_LIST.iterator();
}
public void setSingleReachable() {
super.setSingleReachable();
Main.getClassBundle().analyzeIdentifier(this);
}
public void analyze() {
if (GlobalOptions.verboseLevel > 1)
GlobalOptions.err.println("Analyze: "+this);
String type = getType();
int index = type.indexOf('L');
while (index != -1) {
int end = type.indexOf(';', index);
Main.getClassBundle().reachableClass
(type.substring(index+1, end).replace('/', '.'));
index = type.indexOf('L', end);
}
String[] exceptions = info.getExceptions();
if (exceptions != null) {
for (int i=0; i< exceptions.length; i++)
Main.getClassBundle()
.reachableClass(exceptions[i]);
}
BytecodeInfo code = info.getBytecode();
if (code != null)
codeAnalyzer.analyzeCode(this, code);
}
public Identifier getParent() {
return clazz;
}
public String getFullName() {
return clazz.getFullName() + "." + getName() + "." + getType();
}
public String getFullAlias() {
return clazz.getFullAlias() + "." + getAlias() + "."
+ Main.getClassBundle().getTypeAlias(getType());
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public boolean conflicting(String newAlias) {
return clazz.methodConflicts(this, newAlias);
}
public String toString() {
return "MethodIdentifier "+getFullName();
}
public boolean hasGlobalSideEffects() {
return globalSideEffects;
}
public boolean getLocalSideEffects(int paramNr) {
return globalSideEffects || localSideEffects.get(paramNr);
}
public void setGlobalSideEffects() {
globalSideEffects = true;
}
public void setLocalSideEffects(int paramNr) {
localSideEffects.set(paramNr);
}
/**
* This method does the code transformation. This include
* <ul><li>new slot distribution for locals</li>
* <li>obfuscating transformation of flow</li>
* <li>renaming field, method and class references</li>
* </ul>
*/
boolean wasTransformed = false;
public void doTransformations() {
if (wasTransformed)
throw new jode.AssertError
("doTransformation called on transformed method");
wasTransformed = true;
info.setName(getAlias());
ClassBundle bundle = Main.getClassBundle();
info.setType(bundle.getTypeAlias(type));
if (codeAnalyzer != null) {
BytecodeInfo bytecode = info.getBytecode();
try {
codeAnalyzer.transformCode(bytecode);
CodeTransformer[] trafos = bundle.getPostTransformers();
for (int i = 0; i < trafos.length; i++) {
trafos[i].transformCode(bytecode);
}
} catch (RuntimeException ex) {
ex.printStackTrace(GlobalOptions.err);
bytecode.dumpCode(GlobalOptions.err);
}
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
switch (instr.getOpcode()) {
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
case opc_invokevirtual: {
instr.setReference
(Main.getClassBundle()
.getReferenceAlias(instr.getReference()));
break;
}
case opc_putstatic:
case opc_putfield:
case opc_getstatic:
case opc_getfield: {
instr.setReference
(Main.getClassBundle()
.getReferenceAlias(instr.getReference()));
break;
}
case opc_new:
case opc_checkcast:
case opc_instanceof:
case opc_multianewarray: {
instr.setClazzType
(Main.getClassBundle()
.getTypeAlias(instr.getClazzType()));
break;
}
}
}
Handler[] handlers = bytecode.getExceptionHandlers();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].type != null) {
ClassIdentifier ci = Main.getClassBundle()
.getClassIdentifier(handlers[i].type);
if (ci != null)
handlers[i].type = ci.getFullAlias();
}
}
info.setBytecode(bytecode);
}
String[] exceptions = info.getExceptions();
if (exceptions != null) {
for (int i=0; i< exceptions.length; i++) {
ClassIdentifier ci = Main.getClassBundle()
.getClassIdentifier(exceptions[i]);
if (ci != null)
exceptions[i] = ci.getFullAlias();
}
}
}
}

@ -1,269 +0,0 @@
/* ModifierMatcher Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import java.lang.reflect.Modifier;
public class ModifierMatcher implements IdentifierMatcher, Cloneable {
static final int PUBLIC = Modifier.PUBLIC;
static final int PROTECTED = Modifier.PROTECTED;
static final int PRIVATE = Modifier.PRIVATE;
int[] andMasks;
int[] xorMasks;
public static ModifierMatcher denyAll = new ModifierMatcher(new int[0],
new int[0]);
public static ModifierMatcher allowAll = new ModifierMatcher(0, 0);
/* Invariants:
* \forall i: ~andMasks[i] & xorMasks[i] == 0
* \forall i: entries wo. i does not imply entry nr. i
*/
private ModifierMatcher(int[] ands, int[] xors) {
andMasks = ands;
xorMasks = xors;
}
public ModifierMatcher(int and, int xor) {
andMasks = new int[] { and };
xorMasks = new int[] { xor };
}
private static boolean implies(int and1, int xor1, int and2, int xor2) {
return ((and1 & and2) == and2 && (xor1 & and2) == xor2);
}
private boolean implies(int and, int xor) {
for (int i=0; i < andMasks.length; i++) {
if (!implies(andMasks[i], xorMasks[i], and, xor))
return false;
}
return true;
}
private boolean impliedBy(int and, int xor) {
for (int i=0; i< andMasks.length; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
return true;
}
return false;
}
private boolean implies(ModifierMatcher mm) {
for (int i=0; i < andMasks.length; i++) {
if (!mm.impliedBy(andMasks[i], xorMasks[i]))
return false;
}
return true;
}
public ModifierMatcher and(ModifierMatcher mm) {
if (implies(mm))
return this;
if (mm.implies(this))
return mm;
ModifierMatcher result = denyAll;
for (int i=0; i< andMasks.length; i++)
result = result.or(mm.and(andMasks[i], xorMasks[i]));
return result;
}
public ModifierMatcher or(ModifierMatcher mm) {
if (implies(mm))
return mm;
if (mm.implies(this))
return this;
ModifierMatcher result = this;
for (int i=0; i < mm.andMasks.length; i++)
result = result.or(mm.andMasks[i], mm.xorMasks[i]);
return result;
}
private ModifierMatcher and(int and, int xor) {
if (this.implies(and, xor))
return this;
int newCount = 0;
next_i:
for (int i=0; i < andMasks.length; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
continue next_i;
for (int j=0; j < andMasks.length; j++) {
if (j != i
&& implies(and | andMasks[j], xor | xorMasks[j],
andMasks[i], xorMasks[i]))
continue next_i;
}
newCount++;
}
if (newCount == 0)
return new ModifierMatcher(and, xor);
int[] ands = new int[newCount];
int[] xors = new int[newCount];
int index = 0;
next_i:
for (int i=0; i < newCount; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
continue next_i;
for (int j=0; j < andMasks.length; j++) {
if (j != i
&& implies(and | andMasks[j], xor | xorMasks[j],
andMasks[i], xorMasks[i]))
continue next_i;
}
ands[index] = andMasks[i] | and;
xors[index] = xorMasks[i] | xor;
index++;
}
return new ModifierMatcher(ands, xors);
}
private ModifierMatcher or(int and, int xor) {
int matchIndex = -1;
if (this == denyAll)
return new ModifierMatcher(and, xor);
for (int i=0; i< andMasks.length; i++) {
if (implies(and, xor, andMasks[i], xorMasks[i]))
return this;
if (implies(andMasks[i], xorMasks[i], and, xor)) {
matchIndex = i;
break;
}
}
int[] ands, xors;
if (matchIndex == -1) {
matchIndex = andMasks.length;
ands = new int[matchIndex+1];
xors = new int[matchIndex+1];
System.arraycopy(andMasks, 0, ands, 0, matchIndex);
System.arraycopy(xorMasks, 0, xors, 0, matchIndex);
} else {
ands = (int[]) andMasks.clone();
xors = (int[]) xorMasks.clone();
}
ands[matchIndex] = and;
xors[matchIndex] = xor;
return new ModifierMatcher(ands, xors);
}
/**
* Creates a new ModifierMatcher, that matches only modifiers, we
* also match and also forces the access rights, to be accessModif
* (or less restrictive).
* @param accessModif the access modifier. Use 0 for package access,
* or Modifier.PRIVATE/PROTECTED/PUBLIC.
* @param andAbove allow to be less restrictive.
* @return a new modifier matcher that will also use the given accesses.
*/
public ModifierMatcher forceAccess(int accessModif, boolean andAbove) {
if (andAbove) {
if (accessModif == Modifier.PRIVATE)
return this;
if (accessModif == 0)
return this.and(Modifier.PRIVATE, 0);
ModifierMatcher result = this.and(Modifier.PUBLIC, PUBLIC);
if (accessModif == Modifier.PROTECTED)
return result
.or(this.and(Modifier.PROTECTED, Modifier.PROTECTED));
if (accessModif == Modifier.PUBLIC)
return result;
throw new IllegalArgumentException(""+accessModif);
} else {
if (accessModif == 0)
return this.and(Modifier.PRIVATE |
Modifier.PROTECTED | Modifier.PUBLIC, 0);
else
return this.and(accessModif, accessModif);
}
}
public ModifierMatcher forbidAccess(int accessModif, boolean andAbove) {
if (andAbove) {
if (accessModif == Modifier.PRIVATE)
// This forbids all access.
return denyAll;
if (accessModif == 0)
return this.and(Modifier.PRIVATE, Modifier.PRIVATE);
if (accessModif == Modifier.PROTECTED)
return this.and(Modifier.PROTECTED | Modifier.PUBLIC, 0);
if (accessModif == Modifier.PUBLIC)
return this.and(Modifier.PUBLIC, 0);
throw new IllegalArgumentException(""+accessModif);
} else {
if (accessModif == 0) {
return this.and(Modifier.PRIVATE, Modifier.PRIVATE)
.or(this.and(Modifier.PROTECTED, Modifier.PROTECTED))
.or(this.and(Modifier.PUBLIC, Modifier.PUBLIC));
} else
return this.and(accessModif, 0);
}
}
public final ModifierMatcher forceModifier(int modifier) {
return this.and(modifier, modifier);
}
public final ModifierMatcher forbidModifier(int modifier) {
return this.and(modifier, 0);
}
public final boolean matches(int modifiers) {
for (int i=0; i< andMasks.length; i++)
if ((modifiers & andMasks[i]) == xorMasks[i])
return true;
return false;
}
public final boolean matches(Identifier ident) {
int modifiers;
/* XXX NEW INTERFACE OR ANOTHER METHOD IN IDENTIFIER? */
if (ident instanceof ClassIdentifier)
modifiers = ((ClassIdentifier) ident).info.getModifiers();
else if (ident instanceof MethodIdentifier)
modifiers = ((MethodIdentifier) ident).info.getModifiers();
else if (ident instanceof FieldIdentifier)
modifiers = ((FieldIdentifier) ident).info.getModifiers();
else
return false;
return matches(modifiers);
}
public final boolean matchesSub(Identifier ident, String name) {
return true;
}
public final String getNextComponent(Identifier ident) {
return null;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new IncompatibleClassChangeError(getClass().getName());
}
}
}

@ -1,109 +0,0 @@
/* AndIdentifierMatcher Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Collection;
public class MultiIdentifierMatcher implements IdentifierMatcher, OptionHandler {
/**
* Useful constant for giving to the constructor.
*/
public static boolean OR = true;
/**
* Useful constant for giving to the constructor.
*/
public static boolean AND = false;
IdentifierMatcher[] matchers;
boolean isOr;
/**
* Create an empty MultiIdentifierMatcher.
*/
public MultiIdentifierMatcher() {
this.matchers = new IdentifierMatcher[0];
}
/**
* Create an IdentifierMatcher out of other matchers.
* @param isOr if true, match should return the logical (shortcut)
* or of the underlying matchers, if false it returns the logical and.
* @param matchers the underlying matchers
*/
public MultiIdentifierMatcher(boolean isOr,
IdentifierMatcher[] matchers) {
this.isOr = isOr;
this.matchers = matchers;
}
public void setOption(String option, Collection values) {
if (option.equals("or")) {
isOr = true;
matchers = (IdentifierMatcher[])
values.toArray(new IdentifierMatcher[values.size()]);
} else if (option.equals("and")) {
isOr = false;
matchers = (IdentifierMatcher[])
values.toArray(new IdentifierMatcher[values.size()]);
} else
throw new IllegalArgumentException("Invalid option `"+option+"'.");
}
public boolean matches(Identifier ident) {
for (int i=0; i< matchers.length; i++) {
if (matchers[i].matches(ident) == isOr)
return isOr;
}
return !isOr;
}
public boolean matchesSub(Identifier ident, String name) {
for (int i=0; i< matchers.length; i++) {
if (matchers[i].matchesSub(ident, name) == isOr)
return isOr;
}
return !isOr;
}
public String getNextComponent(Identifier ident) {
if (isOr == AND) {
for (int i=0; i< matchers.length; i++) {
String next = matchers[i].getNextComponent(ident);
if (next != null && matchesSub(ident, next))
return next;
}
return null;
}
// OR case
String next = null;
for (int i = 0; i < matchers.length; i++) {
if (!matchesSub(ident, null))
continue;
if (next != null
&& matchers[i].getNextComponent(ident) != next)
return null;
next = matchers[i].getNextComponent(ident);
if (next == null)
return null;
}
return next;
}
}

@ -1,98 +0,0 @@
/* NameSwapper Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashSet;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.Random;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
public class NameSwapper implements Renamer {
private Random rand;
private Set packs, clazzes, methods, fields, locals;
public NameSwapper(boolean swapAll, long seed) {
if (swapAll) {
packs = clazzes = methods = fields = locals = new HashSet();
} else {
packs = new HashSet();
clazzes = new HashSet();
methods = new HashSet();
fields = new HashSet();
locals = new HashSet();
}
}
public NameSwapper(boolean swapAll) {
this(swapAll, System.currentTimeMillis());
}
private class NameGenerator implements Iterator {
Collection pool;
NameGenerator(Collection c) {
pool = c;
}
public boolean hasNext() {
return true;
}
public Object next() {
int pos = rand.nextInt(pool.size());
Iterator i = pool.iterator();
while (pos > 0)
i.next();
return (String) i.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
public final Collection getCollection(Identifier ident) {
if (ident instanceof PackageIdentifier)
return packs;
else if (ident instanceof ClassIdentifier)
return clazzes;
else if (ident instanceof MethodIdentifier)
return methods;
else if (ident instanceof FieldIdentifier)
return fields;
else if (ident instanceof LocalIdentifier)
return locals;
else
throw new IllegalArgumentException(ident.getClass().getName());
}
public final void addIdentifierName(Identifier ident) {
getCollection(ident).add(ident.getName());
}
public Iterator generateNames(Identifier ident) {
return new NameGenerator(getCollection(ident));
}
}

@ -1,27 +0,0 @@
/* OptionHandler Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Collection;
public interface OptionHandler {
public void setOption(String option, Collection values)
throws IllegalArgumentException;
}

@ -1,454 +0,0 @@
/* PackageIdentifier Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.GlobalOptions;
import jode.bytecode.ClassInfo;
import jode.bytecode.FieldInfo;
import jode.bytecode.MethodInfo;
import java.lang.reflect.Modifier;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Iterator;
public class PackageIdentifier extends Identifier {
ClassBundle bundle;
PackageIdentifier parent;
String name;
String fullName;
boolean loadOnDemand;
Map loadedClasses;
public PackageIdentifier(ClassBundle bundle,
PackageIdentifier parent,
String fullName, String name) {
super(name);
this.bundle = bundle;
this.parent = parent;
this.fullName = fullName;
this.name = name;
this.loadedClasses = new HashMap();
}
/**
* Marks the parent package as preserved, too.
*/
protected void setSinglePreserved() {
if (parent != null)
parent.setPreserved();
}
public void setLoadOnDemand() {
if (loadOnDemand)
return;
loadOnDemand = true;
if ((Main.stripping & Main.STRIP_UNREACH) == 0) {
String fullNamePrefix =
(fullName.length() > 0) ? fullName + "." : "";
// Load all classes and packages now, so they don't get stripped
Enumeration enum =
ClassInfo.getClassesAndPackages(getFullName());
while (enum.hasMoreElements()) {
String subclazz = ((String)enum.nextElement()).intern();
if (loadedClasses.containsKey(subclazz))
continue;
String subFull = (fullNamePrefix + subclazz).intern();
if (ClassInfo.isPackage(subFull)) {
PackageIdentifier ident = new PackageIdentifier
(bundle, this, subFull, subclazz);
loadedClasses.put(subclazz, ident);
ident.setLoadOnDemand();
} else {
ClassIdentifier ident = new ClassIdentifier
(this, subFull, subclazz, ClassInfo.forName(subFull));
if (GlobalOptions.verboseLevel > 1)
GlobalOptions.err.println("preloading Class "
+ subFull);
loadedClasses.put(subclazz, ident);
bundle.addClassIdentifier(ident);
((ClassIdentifier) ident).initClass();
}
}
// Everything is loaded, we don't need to load on demand anymore.
loadOnDemand = false;
}
}
public Identifier getIdentifier(String name) {
if (loadOnDemand) {
Identifier ident = loadClass(name);
return ident;
}
int index = name.indexOf('.');
if (index == -1)
return (Identifier) loadedClasses.get(name);
else {
PackageIdentifier pack = (PackageIdentifier)
loadedClasses.get(name.substring(0, index));
if (pack != null)
return pack.getIdentifier(name.substring(index+1));
else
return null;
}
}
public Identifier loadClass(String name) {
int index = name.indexOf('.');
if (index == -1) {
Identifier ident = (Identifier) loadedClasses.get(name);
if (ident == null) {
String subFull =
(fullName.length() > 0) ? fullName + "."+ name : name;
subFull = subFull.intern();
if (ClassInfo.isPackage(subFull)) {
PackageIdentifier pack
= new PackageIdentifier(bundle, this, subFull, name);
loadedClasses.put(name, pack);
pack.setLoadOnDemand();
ident = pack;
} else if (!ClassInfo.exists(subFull)) {
GlobalOptions.err.println("Warning: Can't find class "
+ subFull);
Thread.dumpStack();
} else {
ident = new ClassIdentifier(this, subFull, name,
ClassInfo.forName(subFull));
loadedClasses.put(name, ident);
bundle.addClassIdentifier(ident);
((ClassIdentifier) ident).initClass();
}
}
return ident;
} else {
String subpack = name.substring(0, index);
PackageIdentifier pack =
(PackageIdentifier) loadedClasses.get(subpack);
if (pack == null) {
String subFull = (fullName.length() > 0)
? fullName + "."+ subpack : subpack;
subFull = subFull.intern();
if (ClassInfo.isPackage(subFull)) {
pack = new PackageIdentifier(bundle, this,
subFull, subpack);
loadedClasses.put(subpack, pack);
if (loadOnDemand)
pack.setLoadOnDemand();
}
}
if (pack != null)
return pack.loadClass(name.substring(index+1));
else
return null;
}
}
public void loadMatchingClasses(IdentifierMatcher matcher) {
String component = matcher.getNextComponent(this);
if (component != null) {
Identifier ident = (Identifier) loadedClasses.get(component);
if (ident == null) {
component = component.intern();
String subFull = (fullName.length() > 0)
? fullName + "."+ component : component;
subFull = subFull.intern();
if (ClassInfo.isPackage(subFull)) {
ident = new PackageIdentifier(bundle, this,
subFull, component);
loadedClasses.put(component, ident);
if (loadOnDemand)
((PackageIdentifier) ident).setLoadOnDemand();
} else if (ClassInfo.exists(subFull)) {
if (GlobalOptions.verboseLevel > 1)
GlobalOptions.err.println("loading Class " +subFull);
ident = new ClassIdentifier(this, subFull, component,
ClassInfo.forName(subFull));
if (loadOnDemand || matcher.matches(ident)) {
loadedClasses.put(component, ident);
bundle.addClassIdentifier(ident);
((ClassIdentifier) ident).initClass();
}
} else {
GlobalOptions.err.println
("Warning: Can't find class/package " + subFull);
}
}
if (ident instanceof PackageIdentifier) {
if (matcher.matches(ident)) {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("loading Package "
+ident.getFullName());
((PackageIdentifier) ident).setLoadOnDemand();
}
if (matcher.matchesSub(ident, null))
((PackageIdentifier) ident).loadMatchingClasses(matcher);
}
} else {
String fullNamePrefix =
(fullName.length() > 0) ? fullName + "." : "";
/* Load all matching classes and packages */
Enumeration enum =
ClassInfo.getClassesAndPackages(getFullName());
while (enum.hasMoreElements()) {
String subclazz = ((String)enum.nextElement()).intern();
if (loadedClasses.containsKey(subclazz))
continue;
String subFull = (fullNamePrefix + subclazz).intern();
if (matcher.matchesSub(this, subclazz)) {
if (ClassInfo.isPackage(subFull)) {
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("loading Package "
+ subFull);
PackageIdentifier ident = new PackageIdentifier
(bundle, this, subFull, subclazz);
loadedClasses.put(subclazz, ident);
if (loadOnDemand || matcher.matches(ident))
ident.setLoadOnDemand();
} else {
ClassIdentifier ident = new ClassIdentifier
(this, subFull, subclazz,
ClassInfo.forName(subFull));
if (loadOnDemand || matcher.matches(ident)) {
if (GlobalOptions.verboseLevel > 1)
GlobalOptions.err.println("loading Class "
+ subFull);
loadedClasses.put(subclazz, ident);
bundle.addClassIdentifier(ident);
((ClassIdentifier) ident).initClass();
}
}
}
}
for (Iterator i = loadedClasses.values().iterator();
i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (ident instanceof PackageIdentifier) {
if (matcher.matches(ident))
((PackageIdentifier) ident).setLoadOnDemand();
if (matcher.matchesSub(ident, null))
((PackageIdentifier) ident)
.loadMatchingClasses(matcher);
}
}
}
}
public void applyPreserveRule(IdentifierMatcher preserveRule) {
if (loadOnDemand)
loadMatchingClasses(preserveRule);
super.applyPreserveRule(preserveRule);
}
/**
* @return the full qualified name.
*/
public String getFullName() {
return fullName;
}
/**
* @return the full qualified alias.
*/
public String getFullAlias() {
if (parent != null) {
if (parent.getFullAlias().length() > 0)
return parent.getFullAlias() + "." + getAlias();
else
return getAlias();
}
return "";
}
public String findAlias(String className) {
int index = className.indexOf('.');
if (index == -1) {
Identifier ident = getIdentifier(className);
if (ident != null)
return ident.getFullAlias();
} else {
Identifier pack = getIdentifier(className.substring(0, index));
if (pack != null)
return ((PackageIdentifier)pack)
.findAlias(className.substring(index+1));
}
return className;
}
public void buildTable(Renamer renameRule) {
loadOnDemand = false;
super.buildTable(renameRule);
}
public void doTransformations() {
for (Iterator i = loadedClasses.values().iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if (ident instanceof ClassIdentifier) {
((ClassIdentifier) ident).doTransformations();
} else
((PackageIdentifier) ident).doTransformations();
}
}
public void readTable(Map table) {
if (parent != null)
setAlias((String) table.get(getFullName()));
for (Iterator i = loadedClasses.values().iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable())
ident.readTable(table);
}
}
public void writeTable(Map table) {
if (parent != null)
table.put(getFullAlias(), getName());
for (Iterator i = loadedClasses.values().iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if ((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable())
ident.writeTable(table);
}
}
public Identifier getParent() {
return parent;
}
public String getName() {
return name;
}
public String getType() {
return "package";
}
public Iterator getChilds() {
return loadedClasses.values().iterator();
}
public void storeClasses(ZipOutputStream zip) {
for (Iterator i = loadedClasses.values().iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if ((Main.stripping & Main.STRIP_UNREACH) != 0
&& !ident.isReachable()) {
if (GlobalOptions.verboseLevel > 4)
GlobalOptions.err.println("Class/Package "
+ ident.getFullName()
+ " is not reachable");
continue;
}
if (ident instanceof PackageIdentifier)
((PackageIdentifier) ident).storeClasses(zip);
else {
try {
String filename = ident.getFullAlias().replace('.','/')
+ ".class";
zip.putNextEntry(new ZipEntry(filename));
DataOutputStream out = new DataOutputStream
(new BufferedOutputStream(zip));
((ClassIdentifier) ident).storeClass(out);
out.flush();
zip.closeEntry();
} catch (java.io.IOException ex) {
GlobalOptions.err.println("Can't write Class "
+ ident.getName());
ex.printStackTrace(GlobalOptions.err);
}
}
}
}
public void storeClasses(File destination) {
File newDest = (parent == null) ? destination
: new File(destination, getAlias());
if (!newDest.exists() && !newDest.mkdir()) {
GlobalOptions.err.println("Could not create directory "
+newDest.getPath()+", check permissions.");
}
for (Iterator i = loadedClasses.values().iterator(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next();
if ((Main.stripping & Main.STRIP_UNREACH) != 0
&& !ident.isReachable()) {
if (GlobalOptions.verboseLevel > 4)
GlobalOptions.err.println("Class/Package "
+ ident.getFullName()
+ " is not reachable");
continue;
}
if (ident instanceof PackageIdentifier)
((PackageIdentifier) ident)
.storeClasses(newDest);
else {
try {
File file = new File(newDest, ident.getAlias()+".class");
// if (file.exists()) {
// GlobalOptions.err.println
// ("Refuse to overwrite existing class file "
// +file.getPath()+". Remove it first.");
// return;
// }
DataOutputStream out = new DataOutputStream
(new BufferedOutputStream
(new FileOutputStream(file)));
((ClassIdentifier) ident).storeClass(out);
out.close();
} catch (java.io.IOException ex) {
GlobalOptions.err.println("Can't write Class "
+ ident.getName());
ex.printStackTrace(GlobalOptions.err);
}
}
}
}
public String toString() {
return (parent == null) ? "base package" : getFullName();
}
public boolean contains(String newAlias, Identifier except) {
for (Iterator i = loadedClasses.values().iterator(); i.hasNext(); ) {
Identifier ident = (Identifier)i.next();
if (((Main.stripping & Main.STRIP_UNREACH) == 0
|| ident.isReachable())
&& ident != except
&& ident.getAlias().equals(newAlias))
return true;
}
return false;
}
public boolean conflicting(String newAlias) {
return parent.contains(newAlias, this);
}
}

@ -1,26 +0,0 @@
/* ParseException Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
public class ParseException extends Exception {
public ParseException(int linenr, String message) {
super ("line "+linenr+": "+message);
}
}

@ -1,307 +0,0 @@
/* RemovePopAnalyzer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.*;
import jode.AssertError;
import jode.GlobalOptions;
import @COLLECTIONS@.ListIterator;
public class RemovePopAnalyzer implements CodeTransformer, Opcodes {
public RemovePopAnalyzer() {
}
public void transformCode(BytecodeInfo bytecode) {
int poppush[] = new int[2];
ListIterator iter = bytecode.getInstructions().listIterator();
next_pop:
while (iter.hasNext()) {
Instruction popInstr = (Instruction) iter.next();
boolean isPop2 = false;
switch (popInstr.getOpcode()) {
case opc_nop: {
iter.remove();
continue;
}
case opc_pop2:
isPop2 = true;
case opc_pop:
if (popInstr.getPreds() != null)
// Can't handle pop with multiple predecessors
continue next_pop;
Handler[] handlers = bytecode.getExceptionHandlers();
for (int i=0; i < handlers.length; i++)
if (handlers[i].catcher == popInstr)
continue next_pop;
// remove pop, we will insert it again if something
// bad happened.
iter.remove();
// remember position of pop, so we can insert it again.
Instruction popPrevious = (Instruction) iter.previous();
Instruction instr = popPrevious;
int count = 0;
while (true) {
if (instr.getSuccs() != null
|| instr.doesAlwaysJump()) {
instr = null;
break;
}
instr.getStackPopPush(poppush);
if (count < poppush[1]) {
if (count == 0)
break;
int opcode = instr.getOpcode();
/* If this is a dup and the instruction popped is the
* duplicated element, remove the dup and the pop
*/
if (count <= 3 && opcode == (opc_dup + count - 1)) {
iter.remove();
if (!isPop2)
continue next_pop;
// We have to consider a pop instead of a
// pop2 now.
popInstr = new Instruction(opc_pop);
isPop2 = false;
instr = (Instruction) iter.previous();
continue;
}
if (isPop2
&& count > 1 && count <= 4
&& opcode == (opc_dup2 + count-2)) {
iter.remove();
continue next_pop;
}
/* Otherwise popping is not possible */
instr = null;
break;
}
count += poppush[0] - poppush[1];
instr = (Instruction) iter.previous();
}
if (instr == null) {
// We insert the pop at the previous position
while (iter.next() != popPrevious)
{}
if (!isPop2 && popPrevious.getOpcode() == opc_pop) {
// merge pop with popPrevious
iter.set(new Instruction(opc_pop2));
} else
iter.add(popInstr);
continue;
}
int opcode = instr.getOpcode();
switch (opcode) {
case opc_ldc2_w:
case opc_lload: case opc_dload:
if (!isPop2)
throw new AssertError("pop on long");
iter.remove();
continue;
case opc_ldc:
case opc_iload: case opc_fload: case opc_aload:
case opc_dup:
case opc_new:
if (isPop2)
iter.set(new Instruction(opc_pop));
else
iter.remove();
continue;
case opc_iaload: case opc_faload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
case opc_iadd: case opc_fadd:
case opc_isub: case opc_fsub:
case opc_imul: case opc_fmul:
case opc_idiv: case opc_fdiv:
case opc_irem: case opc_frem:
case opc_iand: case opc_ior : case opc_ixor:
case opc_ishl: case opc_ishr: case opc_iushr:
case opc_fcmpl: case opc_fcmpg:
/* We have to pop one entry more. */
iter.next();
iter.add(popInstr);
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop));
continue;
case opc_dup_x1:
iter.set(new Instruction(opc_swap));
iter.next();
if (isPop2)
iter.add(new Instruction(opc_pop));
continue;
case opc_dup2:
if (isPop2) {
iter.remove();
continue;
}
break;
case opc_swap:
if (isPop2) {
iter.set(popInstr);
continue;
}
break;
case opc_lneg: case opc_dneg:
case opc_l2d: case opc_d2l:
case opc_laload: case opc_daload:
if (!isPop2)
throw new AssertError("pop on long");
/* fall through */
case opc_ineg: case opc_fneg:
case opc_i2f: case opc_f2i:
case opc_i2b: case opc_i2c: case opc_i2s:
case opc_newarray: case opc_anewarray:
case opc_arraylength:
case opc_instanceof:
iter.set(popInstr);
continue;
case opc_l2i: case opc_l2f:
case opc_d2i: case opc_d2f:
if (isPop2) {
iter.next();
iter.add(new Instruction(opc_pop));
iter.previous();
iter.previous();
}
iter.set(new Instruction(opc_pop2));
continue;
case opc_ladd: case opc_dadd:
case opc_lsub: case opc_dsub:
case opc_lmul: case opc_dmul:
case opc_ldiv: case opc_ddiv:
case opc_lrem: case opc_drem:
case opc_land: case opc_lor : case opc_lxor:
if (!isPop2)
throw new AssertError("pop on long");
iter.next();
iter.add(popInstr);
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop2));
continue;
case opc_lshl: case opc_lshr: case opc_lushr:
if (!isPop2)
throw new AssertError("pop on long");
iter.next();
iter.add(popInstr);
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop));
continue;
case opc_i2l: case opc_i2d:
case opc_f2l: case opc_f2d:
if (!isPop2)
throw new AssertError("pop on long");
iter.set(new Instruction(opc_pop));
continue;
case opc_lcmp:
case opc_dcmpl: case opc_dcmpg:
iter.next();
iter.add(new Instruction(opc_pop2));
if (isPop2) {
iter.add(new Instruction(opc_pop));
iter.previous();
}
iter.previous();
iter.previous();
iter.set(new Instruction(opc_pop2));
continue;
case opc_getstatic:
case opc_getfield: {
Reference ref = instr.getReference();
int size = TypeSignature.getTypeSize(ref.getType());
if (size == 2 && !isPop2)
throw new AssertError("pop on long");
if (opcode == opc_getfield)
size--;
switch (size) {
case 0:
iter.set(popInstr);
break;
case 1:
if (isPop2) {
iter.set(new Instruction(opc_pop));
break;
}
/* fall through */
case 2:
iter.remove();
}
continue;
}
case opc_multianewarray: {
int dims = instr.getDimensions();
if (--dims > 0) {
iter.next();
while (dims-- > 0) {
iter.add(new Instruction(opc_pop));
iter.previous();
}
iter.previous();
}
iter.set(popInstr);
continue;
}
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
if (TypeSignature.getReturnSize
(instr.getReference().getType()) != 1)
break;
/* fall through */
case opc_checkcast:
if (isPop2) {
/* This is/may be a double pop on a single value
* split it and continue with second half
*/
iter.next();
iter.add(new Instruction(opc_pop));
iter.add(new Instruction(opc_pop));
iter.previous();
continue;
}
}
// append the pop behind the unresolvable opcode.
iter.next();
iter.add(popInstr);
continue;
}
}
}
}

@ -1,32 +0,0 @@
/* Renamer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Iterator;
public interface Renamer {
/**
* Generates a new name.
* @param ident the identifier that should be renamed.
* @param lastName the last name generated for this identifier, or
* null, if no name was generated yet.
*/
public Iterator generateNames(Identifier ident);
}

@ -1,279 +0,0 @@
/* ScriptParser Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.LinkedList;
public class ScriptParser {
static int NO_TOKEN = -2;
static int EOF_TOKEN = -1;
static int STRING_TOKEN = 0;
static int NEW_TOKEN = 1;
static int EQUALS_TOKEN = 2;
static int COMMA_TOKEN = 3;
static int OPENBRACE_TOKEN = 4;
static int CLOSEBRACE_TOKEN = 5;
static int IDENTIFIER_TOKEN = 6;
static int NUMBER_TOKEN = 7;
Scanner scanner;
class Scanner {
BufferedReader input;
String value;
String line;
int column;
int linenr;
int pushback = NO_TOKEN;
public Scanner(Reader i) {
input = new BufferedReader(i);
}
public void readString() throws ParseException {
StringBuffer val = new StringBuffer();
while (column < line.length()) {
char c = line.charAt(column++);
if (c == '"') {
value = val.toString();
return;
}
if (c == '\\') {
c = line.charAt(column++);
switch (c) {
case 'n':
val.append('\n');
break;
case 't':
val.append('\t');
break;
case 'r':
val.append('\r');
break;
case 'u':
if (column+4 <= line.length()) {
try {
char uni = (char) Integer.parseInt
(line.substring(column, column+4), 16);
column += 4;
val.append(uni);
} catch (NumberFormatException ex) {
throw new ParseException
(linenr,
"Invalid unicode escape character");
}
} else
throw new ParseException
(linenr,
"Invalid unicode escape character");
break;
default:
val.append(c);
}
} else
val.append(c);
}
throw new ParseException(linenr,
"String spans over multiple lines");
}
public void readIdentifier() {
int start = column-1;
while (column < line.length()
&& Character.isUnicodeIdentifierPart(line.charAt(column)))
column++;
value = line.substring(start, column);
}
public void readNumber() {
boolean hex = false;
int start = column-1;
/* special case for hex numbers */
if (line.charAt(start) == '0' && line.charAt(column) == 'x') {
column++;
hex = true;
}
while (column < line.length()) {
char c = line.charAt(column);
if (!Character.isDigit(c)) {
if (!hex)
break;
if ((c < 'A' || c > 'F') && (c < 'a' || c > 'f'))
break;
}
column++;
}
value = line.substring(start, column);
}
public void pushbackToken(int token) {
if (pushback != NO_TOKEN)
throw new IllegalStateException
("Can only handle one pushback");
pushback = token;
}
public int getToken() throws ParseException, IOException {
if (pushback != NO_TOKEN) {
int result = pushback;
pushback = NO_TOKEN;
return result;
}
value = null;
while (true) {
if (line == null) {
line = input.readLine();
if (line == null)
return EOF_TOKEN;
linenr++;
column = 0;
}
while (column < line.length()) {
char c = line.charAt(column++);
if (Character.isWhitespace(c))
continue;
if (c == '#')
// this is a comment, skip this line
break;
if (c == '=')
return EQUALS_TOKEN;
if (c == ',')
return COMMA_TOKEN;
if (c == '{')
return OPENBRACE_TOKEN;
if (c == '}')
return CLOSEBRACE_TOKEN;
if (c == '"') {
readString();
return STRING_TOKEN;
}
if (Character.isDigit(c) || c == '+' || c == '-') {
readNumber();
return NUMBER_TOKEN;
}
if (Character.isUnicodeIdentifierStart(c)) {
readIdentifier();
if (value.equals("new"))
return NEW_TOKEN;
return IDENTIFIER_TOKEN;
}
throw new ParseException
(linenr, "Illegal character `"+c+"'");
}
line = null;
}
}
public String getValue() {
return value;
}
public int getLineNr() {
return linenr;
}
}
public ScriptParser(Reader reader) {
this.scanner = new Scanner(reader);
}
public Object parseClass() throws ParseException, IOException {
int linenr = scanner.getLineNr();
int token = scanner.getToken();
if (token != IDENTIFIER_TOKEN)
throw new ParseException(linenr, "Class name expected");
Object instance;
try {
Class clazz = Class.forName("jode.obfuscator."+scanner.getValue());
instance = clazz.newInstance();
} catch (ClassNotFoundException ex) {
throw new ParseException(scanner.getLineNr(),
"Class `"+scanner.getValue()
+"' not found");
} catch (Exception ex) {
throw new ParseException(scanner.getLineNr(),
"Class `"+scanner.getValue()
+"' not valid: "+ex.getMessage());
}
token = scanner.getToken();
if (token == OPENBRACE_TOKEN) {
if (!(instance instanceof OptionHandler))
throw new ParseException
(scanner.getLineNr(),
"Class `"+instance.getClass().getName()
+"' doesn't handle options.");
parseOptions((OptionHandler) instance);
if (scanner.getToken() != CLOSEBRACE_TOKEN)
throw new ParseException(scanner.getLineNr(), "`}' expected");
} else
scanner.pushbackToken(token);
return instance;
}
public void parseOptions(OptionHandler optionHandler)
throws ParseException, IOException
{
int token = scanner.getToken();
while (true) {
if (token == EOF_TOKEN || token == CLOSEBRACE_TOKEN) {
scanner.pushbackToken(token);
return;
}
if (token != IDENTIFIER_TOKEN)
throw new ParseException(scanner.getLineNr(),
"identifier expected");
String ident = scanner.getValue();
if (scanner.getToken() != EQUALS_TOKEN)
throw new ParseException(scanner.getLineNr(),
"equal sign expected");
int linenr = scanner.getLineNr();
Collection values = new LinkedList();
do {
token = scanner.getToken();
if (token == NEW_TOKEN) {
values.add(parseClass());
} else if (token == STRING_TOKEN) {
values.add(scanner.getValue());
} else if (token == NUMBER_TOKEN) {
values.add(new Integer(scanner.getValue()));
}
token = scanner.getToken();
} while (token == COMMA_TOKEN);
try {
optionHandler.setOption(ident, values);
} catch (IllegalArgumentException ex) {
throw new ParseException(linenr,
optionHandler.getClass().getName()
+": "+ex.getMessage());
} catch (RuntimeException ex) {
throw new ParseException(linenr,
optionHandler.getClass().getName()
+": Illegal value: "
+ex.getClass().getName()
+": "+ex.getMessage());
}
}
}
}

@ -1,182 +0,0 @@
/* SimpleAnalyzer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import jode.bytecode.Handler;
import jode.bytecode.Opcodes;
import jode.bytecode.ClassInfo;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.Instruction;
import jode.bytecode.Reference;
import jode.bytecode.TypeSignature;
import jode.GlobalOptions;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
public Identifier canonizeReference(Instruction instr) {
Reference ref = instr.getReference();
Identifier ident = Main.getClassBundle().getIdentifier(ref);
String clName = ref.getClazz();
String realClazzName;
if (ident != null) {
ClassIdentifier clazz = (ClassIdentifier)ident.getParent();
realClazzName = "L" + (clazz.getFullName()
.replace('.', '/')) + ";";
} else {
/* We have to look at the ClassInfo's instead, to
* point to the right method.
*/
ClassInfo clazz;
if (clName.charAt(0) == '[') {
/* Arrays don't define new methods (well clone(),
* but that can be ignored).
*/
clazz = ClassInfo.javaLangObject;
} else {
clazz = ClassInfo.forName
(clName.substring(1, clName.length()-1)
.replace('/','.'));
}
if (instr.getOpcode() >= opc_invokevirtual) {
while (clazz != null
&& clazz.findMethod(ref.getName(),
ref.getType()) == null)
clazz = clazz.getSuperclass();
} else {
while (clazz != null
&& clazz.findField(ref.getName(),
ref.getType()) == null)
clazz = clazz.getSuperclass();
}
if (clazz == null) {
GlobalOptions.err.println("WARNING: Can't find reference: "
+ref);
realClazzName = clName;
} else
realClazzName = "L" + clazz.getName().replace('.', '/') + ";";
}
if (!realClazzName.equals(ref.getClazz())) {
ref = Reference.getReference(realClazzName,
ref.getName(), ref.getType());
instr.setReference(ref);
}
return ident;
}
/**
* Reads the opcodes out of the code info and determine its
* references
* @return an enumeration of the references.
*/
public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) {
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
switch (instr.getOpcode()) {
case opc_checkcast:
case opc_instanceof:
case opc_multianewarray: {
String clName = instr.getClazzType();
int i = 0;
while (i < clName.length() && clName.charAt(i) == '[')
i++;
if (i < clName.length() && clName.charAt(i) == 'L') {
clName = clName.substring(i+1, clName.length()-1)
.replace('/','.');
Main.getClassBundle().reachableClass(clName);
}
break;
}
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
case opc_invokevirtual:
case opc_putstatic:
case opc_putfield:
m.setGlobalSideEffects();
/* fall through */
case opc_getstatic:
case opc_getfield: {
Identifier ident = canonizeReference(instr);
if (ident != null) {
if (instr.getOpcode() == opc_putstatic
|| instr.getOpcode() == opc_putfield) {
FieldIdentifier fi = (FieldIdentifier) ident;
if (fi != null && !fi.isNotConstant())
fi.setNotConstant();
} else if (instr.getOpcode() == opc_invokevirtual
|| instr.getOpcode() == opc_invokeinterface) {
((ClassIdentifier) ident.getParent())
.reachableReference(instr.getReference(), true);
} else {
ident.setReachable();
}
}
break;
}
}
}
Handler[] handlers = bytecode.getExceptionHandlers();
for (int i=0; i< handlers.length; i++) {
if (handlers[i].type != null)
Main.getClassBundle()
.reachableClass(handlers[i].type);
}
}
public void transformCode(BytecodeInfo bytecode) {
for (ListIterator iter = bytecode.getInstructions().listIterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_putstatic
|| instr.getOpcode() == opc_putfield) {
Reference ref = instr.getReference();
FieldIdentifier fi = (FieldIdentifier)
Main.getClassBundle().getIdentifier(ref);
if (fi != null
&& (Main.stripping & Main.STRIP_UNREACH) != 0
&& !fi.isReachable()) {
/* Replace instruction with pop opcodes. */
int stacksize =
(instr.getOpcode()
== Instruction.opc_putstatic) ? 0 : 1;
stacksize += TypeSignature.getTypeSize(ref.getType());
switch (stacksize) {
case 1:
iter.set(new Instruction(Instruction.opc_pop));
break;
case 2:
iter.set(new Instruction(Instruction.opc_pop2));
break;
case 3:
iter.set(new Instruction(Instruction.opc_pop2));
iter.add(new Instruction(Instruction.opc_pop));
break;
}
}
}
}
}
}

@ -1,141 +0,0 @@
/* StrongRenamer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Iterator;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
public class StrongRenamer implements Renamer, OptionHandler {
static String[] idents = {
"Package", "Class", "Field", "Method", "Local"
};
static String[] parts = {
"Start", "Part"
};
String charsets[][];
public StrongRenamer() {
charsets = new String[idents.length][parts.length];
for (int i=0; i< idents.length; i++)
for (int j=0; j< parts.length; j++)
charsets[i][j] = "abcdefghijklmnopqrstuvwxyz";
}
public void setOption(String option, Collection values) {
if (option.startsWith("charset")) {
Object value = values.iterator().next();
if (values.size() != 1 || !(value instanceof String))
throw new IllegalArgumentException
("Only string parameter are supported.");
String set = (String) value;
String remOpt = option.substring("charset".length());
int part = -1, ident = -1;
if (remOpt.length() > 0) {
for (int i=0; i < idents.length; i++) {
if (remOpt.startsWith(idents[i])) {
remOpt = option.substring(idents[i].length());
ident = i;
break;
}
}
}
if (remOpt.length() > 0) {
for (int j=0; j < parts.length; j++) {
if (remOpt.startsWith(parts[j])) {
remOpt = option.substring(parts[j].length());
part = j;
break;
}
}
}
if (remOpt.length() > 0)
throw new IllegalArgumentException("Invalid charset `"
+option+"'");
for (int i = 0; i < idents.length; i++) {
if (ident >= 0 && ident != i)
continue;
for (int j = 0; j < parts.length; j++) {
if (part >= 0 && part != j)
continue;
charsets[i][j] = set;
}
}
} else
throw new IllegalArgumentException("Invalid option `"
+option+"'");
}
public Iterator generateNames(Identifier ident) {
final String[] currCharset;
if (ident instanceof PackageIdentifier)
currCharset = charsets[0];
else if (ident instanceof PackageIdentifier)
currCharset = charsets[1];
else if (ident instanceof ClassIdentifier)
currCharset = charsets[2];
else if (ident instanceof FieldIdentifier)
currCharset = charsets[3];
else if (ident instanceof MethodIdentifier)
currCharset = charsets[4];
else if (ident instanceof LocalIdentifier)
currCharset = charsets[5];
else
throw new IllegalArgumentException(ident.getClass().getName());
return new Iterator() {
char[] name = null;
public boolean hasNext() {
return true;
}
public Object next() {
if (name == null) {
name = new char[] { currCharset[0].charAt(0) };
return new String(name);
}
int pos = name.length - 1;
String charset = currCharset[1];
while (pos >= 0) {
if (pos == 0)
charset = currCharset[0];
int index = charset.indexOf(name[pos]) + 1;
if (index < charset.length()) {
name[pos] = charset.charAt(index);
return new String(name);
}
name[pos--] = charset.charAt(0);
}
name = new char[name.length+1];
name[0] = currCharset[0].charAt(0);
char firstCont = currCharset[1].charAt(0);
for (int i=1; i <name.length; i++)
name[i] = firstCont;
return new String(name);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

@ -1,76 +0,0 @@
/* TranslationTable Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.TreeMap;
import @COLLECTIONS@.Iterator;
///#ifndef JDK12
import @COLLECTIONS@.Comparator;
///#endif
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.IOException;
public class TranslationTable extends TreeMap {
///#ifndef JDK12
public TranslationTable() {
super(createStringComparator());
}
private static Comparator createStringComparator() {
return new Comparator() {
public int compare(Object o1, Object o2) {
return ((String) o1).compareTo((String) o2);
}
};
}
///#endif
public void load(InputStream in) throws IOException {
BufferedReader reader =
new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
if (line.charAt(0) == '#')
continue;
int delim = line.indexOf('=');
String key = line.substring(0, delim);
String value = line.substring(delim+1);
put(key, value);
}
}
public void store(OutputStream out) throws IOException {
PrintWriter writer = new PrintWriter(out);
for (Iterator i = entrySet().iterator(); i.hasNext(); ) {
Map.Entry e = (Map.Entry) i.next();
writer.println(e.getKey()+"="+e.getValue());
}
writer.flush();
}
}

@ -1,41 +0,0 @@
/* UniqueRenamer Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Iterator;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
public class UniqueRenamer implements Renamer {
static int serialnr = 0;
public Iterator generateNames(Identifier ident) {
return new Iterator() {
public boolean hasNext() {
return true;
}
public Object next() {
return "xxx" + serialnr++;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}

@ -1,108 +0,0 @@
/* WildCard Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import @COLLECTIONS@.Collection;
public class WildCard implements IdentifierMatcher, OptionHandler {
String wildcard;
int firstStar;
public WildCard() {
}
public WildCard(String wild) {
wildcard = wild;
firstStar = wildcard.indexOf('*');
}
public void setOption(String option, Collection values) {
if (option.equals("value")) {
if (values.size() != 1)
throw new IllegalArgumentException
("Wildcard supports only one value.");
wildcard = (String) values.iterator().next();
firstStar = wildcard.indexOf('*');
} else
throw new IllegalArgumentException("Invalid option `"+option+"'.");
}
public String getNextComponent(Identifier ident) {
String prefix = ident.getFullName();
if (prefix.length() > 0)
prefix += ".";
int lastDot = prefix.length();
if (!wildcard.startsWith(prefix))
return null;
int nextDot = wildcard.indexOf('.', lastDot);
if (nextDot > 0
&& (nextDot <= firstStar || firstStar == -1))
return wildcard.substring(lastDot, nextDot);
else if (firstStar == -1)
return wildcard.substring(lastDot);
else
return null;
}
public boolean matchesSub(Identifier ident, String subident) {
String prefix = ident.getFullName();
if (prefix.length() > 0)
prefix += ".";
if (subident != null)
prefix += subident;
if (firstStar == -1 || firstStar >= prefix.length())
return wildcard.startsWith(prefix);
return prefix.startsWith(wildcard.substring(0, firstStar));
}
public boolean matches(Identifier ident) {
String test = ident.getFullName();
if (firstStar == -1) {
if (wildcard.equals(test)) {
return true;
}
return false;
}
if (!test.startsWith(wildcard.substring(0, firstStar)))
return false;
test = test.substring(firstStar);
int lastWild = firstStar;
int nextWild;
while ((nextWild = wildcard.indexOf('*', lastWild + 1)) != -1) {
String pattern = wildcard.substring(lastWild+1, nextWild);
while (!test.startsWith(pattern)) {
if (test.length() == 0)
return false;
test = test.substring(1);
}
test = test.substring(nextWild - lastWild - 1);
lastWild = nextWild;
}
return test.endsWith(wildcard.substring(lastWild+1));
}
public String toString() {
return "Wildcard "+wildcard;
}
}

@ -1,2 +0,0 @@
Makefile
Makefile.in

@ -1,270 +0,0 @@
/* HierarchyTreeModel Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.swingui;
import jode.Decompiler;
import jode.bytecode.ClassInfo;
import @JAVAX_SWING@.JProgressBar;
import @JAVAX_SWING@.tree.TreeModel;
import @JAVAX_SWING@.tree.TreePath;
import @JAVAX_SWING@.event.TreeModelListener;
import @JAVAX_SWING@.event.TreeModelEvent;
import @COLLECTIONEXTRA@.Comparable;
import @COLLECTIONS@.TreeSet;
import @COLLECTIONS@.Collection;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashSet;
import java.util.Enumeration;
import java.util.NoSuchElementException;
public class HierarchyTreeModel implements TreeModel, Runnable {
static final int MAX_PACKAGE_LEVEL = 10;
TreeElement root = new TreeElement("");
Set listeners = new HashSet();
JProgressBar progressBar;
Main main;
class TreeElement implements Comparable {
String fullName;
TreeSet childs;
boolean inClassPath = false;
public TreeElement(String fqn) {
this.fullName = fqn;
childs = new TreeSet();
}
public String getFullName() {
return fullName;
}
public void addChild(TreeElement child) {
childs.add(child);
}
public Collection getChilds() {
return childs;
}
public String toString() {
return fullName;
}
public int compareTo(Object o) {
TreeElement other = (TreeElement) o;
return fullName.compareTo(other.fullName);
}
public boolean equals(Object o) {
return (o instanceof TreeElement)
&& fullName.equals(((TreeElement)o).fullName);
}
public int hashCode() {
return fullName.hashCode();
}
}
private TreeElement handleClass(HashMap classes, ClassInfo clazz) {
if (clazz == null)
return root;
TreeElement elem = (TreeElement) classes.get(clazz);
if (elem != null)
return elem;
elem = new TreeElement(clazz.getName());
classes.put(clazz, elem);
if (!clazz.isInterface()) {
ClassInfo superClazz = clazz.getSuperclass();
handleClass(classes, superClazz).addChild(elem);
}
ClassInfo[] ifaces = clazz.getInterfaces();
for (int i=0; i < ifaces.length; i++)
handleClass(classes, ifaces[i]).addChild(elem);
if (ifaces.length == 0 && clazz.isInterface())
root.addChild(elem);
return elem;
}
public int readPackage(int depth, HashMap classes, String packageName,
int count) {
if (depth++ >= MAX_PACKAGE_LEVEL)
return count;
String prefix = packageName.length() == 0 ? "" : packageName + ".";
Enumeration enum =
ClassInfo.getClassesAndPackages(packageName);
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String name = (String)enum.nextElement();
String fqn = prefix + name;
if (ClassInfo.isPackage(fqn)) {
count = readPackage(depth, classes, fqn, count);
} else {
TreeElement elem = handleClass(classes,
ClassInfo.forName(fqn));
if (progressBar != null)
progressBar.setValue(++count);
elem.inClassPath = true;
}
}
return count;
}
public int countClasses(int depth, String packageName) {
if (depth++ >= MAX_PACKAGE_LEVEL)
return 0;
int number = 0;
String prefix = packageName.length() == 0 ? "" : packageName + ".";
Enumeration enum =
ClassInfo.getClassesAndPackages(packageName);
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String name = (String)enum.nextElement();
String fqn = prefix + name;
if (ClassInfo.isPackage(fqn)) {
number += countClasses(depth, fqn);
} else {
number++;
}
}
return number;
}
public HierarchyTreeModel(Main main) {
this.main = main;
this.progressBar = null;
rebuild();
}
public HierarchyTreeModel(Main main, JProgressBar progressBar) {
this.main = main;
this.progressBar = progressBar;
rebuild();
}
public void rebuild() {
Thread t = new Thread(this);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
public void run() {
if (progressBar != null) {
progressBar.setMinimum(0);
progressBar.setMaximum(countClasses(0, ""));
}
readPackage(0, new HashMap(), "", 0);
TreeModelListener[] ls;
synchronized (listeners) {
ls = (TreeModelListener[])
listeners.toArray(new TreeModelListener[listeners.size()]);
}
TreeModelEvent ev = new TreeModelEvent(this, new Object[] { root });
for (int i=0; i< ls.length; i++)
ls[i].treeStructureChanged(ev);
main.reselect();
}
public void addTreeModelListener(TreeModelListener l) {
listeners.add(l);
}
public void removeTreeModelListener(TreeModelListener l) {
listeners.remove(l);
}
public void valueForPathChanged(TreePath path, Object newValue) {
// we don't allow values
}
public Object getChild(Object parent, int index) {
Iterator iter = ((TreeElement) parent).getChilds().iterator();
for (int i=0; i< index; i++)
iter.next();
return iter.next();
}
public int getChildCount(Object parent) {
return ((TreeElement) parent).getChilds().size();
}
public int getIndexOfChild(Object parent, Object child) {
Iterator iter = ((TreeElement) parent).getChilds().iterator();
int i=0;
while (iter.next() != child)
i++;
return i;
}
public Object getRoot() {
return root;
}
public boolean isLeaf(Object node) {
return ((TreeElement) node).getChilds().isEmpty();
}
public boolean isValidClass(Object node) {
return ((TreeElement) node).inClassPath;
}
public String getFullName(Object node) {
return ((TreeElement) node).getFullName();
}
public TreePath getPath(String fullName) {
if (fullName == null || fullName.length() == 0)
return new TreePath(root);
int length = 2;
ClassInfo ci = ClassInfo.forName(fullName);
while (ci.getSuperclass() != null) {
length++;
ci = ci.getSuperclass();
}
TreeElement[] path = new TreeElement[length];
path[0] = root;
int nr = 0;
next_component:
while (nr < length-1) {
ci = ClassInfo.forName(fullName);
for (int i=2; i < length - nr; i++)
ci = ci.getSuperclass();
Iterator iter = path[nr].getChilds().iterator();
while (iter.hasNext()) {
TreeElement te = (TreeElement) iter.next();
if (te.getFullName().equals(ci.getName())) {
path[++nr] = te;
continue next_component;
}
}
return null;
}
return new TreePath(path);
}
}

@ -1,353 +0,0 @@
/* Main Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.swingui;
import jode.GlobalOptions;
import jode.decompiler.*;
import jode.bytecode.ClassInfo;
import jode.bytecode.SearchPath;
import @JAVAX_SWING@.*;
import @JAVAX_SWING@.event.*;
import @JAVAX_SWING@.tree.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Main
implements ActionListener, Runnable, TreeSelectionListener {
JFrame frame;
JTree classTree;
JPanel statusLine;
PackagesTreeModel packModel;
HierarchyTreeModel hierModel;
JTextArea sourcecodeArea, errorArea;
Thread decompileThread;
String currentClassPath, lastClassName;
JProgressBar progressBar;
boolean hierarchyTree;
public Main(String classpath) {
setClasspath(classpath);
frame = new JFrame(GlobalOptions.copyright);
fillContentPane(frame.getContentPane());
addMenu(frame);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void show() {
frame.pack();
frame.show();
}
public void fillContentPane(Container contentPane) {
statusLine = new JPanel();
hierarchyTree = false;
packModel = new PackagesTreeModel(this);
hierModel = null;
Font monospaced = new Font("monospaced", Font.PLAIN, 12);
classTree = new JTree(packModel);
classTree.setRootVisible(false);
DefaultTreeSelectionModel selModel = new DefaultTreeSelectionModel();
selModel.setSelectionMode(selModel.SINGLE_TREE_SELECTION);
classTree.setSelectionModel(selModel);
classTree.addTreeSelectionListener(this);
JScrollPane spClassTree = new JScrollPane(classTree);
sourcecodeArea = new JTextArea(20, 80);
sourcecodeArea.setFont(monospaced);
JScrollPane spText = new JScrollPane(sourcecodeArea);
errorArea = new JTextArea(3, 80);
errorArea.setFont(monospaced);
JScrollPane spError = new JScrollPane(errorArea);
JSplitPane rightPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
spText, spError);
JSplitPane allPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
spClassTree, rightPane);
contentPane.setLayout(new BorderLayout());
contentPane.add(allPane, BorderLayout.CENTER);
contentPane.add(statusLine, BorderLayout.SOUTH);
progressBar = new JProgressBar();
statusLine.add(progressBar);
rightPane.setDividerLocation(300);
rightPane.setDividerSize(4);
allPane.setDividerLocation(200);
allPane.setDividerSize(4);
GlobalOptions.err = new PrintWriter
(new BufferedWriter(new AreaWriter(errorArea)), true);
}
public synchronized void valueChanged(TreeSelectionEvent e) {
if (decompileThread != null)
return;
TreePath path = e.getNewLeadSelectionPath();
if (path == null)
return;
Object node = path.getLastPathComponent();
if (node != null) {
if (hierarchyTree && hierModel.isValidClass(node))
lastClassName = hierModel.getFullName(node);
else if (!hierarchyTree && packModel.isValidClass(node))
lastClassName = packModel.getFullName(node);
else
return;
decompileThread = new Thread(this);
decompileThread.setPriority(Thread.MIN_PRIORITY);
sourcecodeArea.setText("Please wait, while decompiling...\n");
decompileThread.start();
}
}
public synchronized void actionPerformed(ActionEvent e) {
if (e.getSource() == classTree && decompileThread == null) {
// startButton.setEnabled(false);
decompileThread = new Thread(this);
sourcecodeArea.setText("Please wait, while decompiling...\n");
decompileThread.start();
// } else if (e.getSource() == saveButton) {
// if (frame == null)
// frame = new Frame(); //XXX
// FileDialog fd = new FileDialog(frame,
// "Save decompiled code",
// FileDialog.SAVE);
// fd.setFile(lastClassName.substring
// (lastClassName.lastIndexOf('.')+1).concat(".java"));
// fd.show();
// String fileName = fd.getFile();
// if (fileName == null)
// return;
// try {
// File f = new File(new File(fd.getDirectory()), fileName);
// FileWriter out = new FileWriter(f);
// out.write(sourcecodeArea.getText());
// out.close();
// } catch (IOException ex) {
// errorArea.setText("");
// GlobalOptions.err.println("Couldn't write to file "
// + fileName + ": ");
// ex.printStackTrace(GlobalOptions.err);
// }
}
}
public class AreaWriter extends Writer {
boolean initialized = false;
private JTextArea area;
public AreaWriter(JTextArea a) {
area = a;
}
public void write(char[] b, int off, int len) throws IOException {
if (!initialized) {
area.setText("");
initialized = true;
}
///#ifdef AWT10
/// area.appendText(new String(b, off, len));
///#else
area.append(new String(b, off, len));
///#endif
}
public void flush() {
}
public void close() {
}
}
public void run() {
// Decompiler.isVerbose = verboseCheck.getState();
// if (prettyCheck.getState())
// Decompiler.options |= Decompiler.OPTION_PRETTY;
// else
// Decompiler.options &= ~Decompiler.OPTION_PRETTY;
errorArea.setText("");
// saveButton.setEnabled(false);
ImportHandler imports = new ImportHandler();
try {
ClassInfo clazz = ClassInfo.forName(lastClassName);
imports.init(lastClassName);
ClassAnalyzer clazzAna = new ClassAnalyzer(null, clazz, imports);
clazzAna.analyze();
clazzAna.analyzeInnerClasses();
clazzAna.makeDeclaration();
sourcecodeArea.setText("");
TabbedPrintWriter writer =
new TabbedPrintWriter
(new BufferedWriter
(new AreaWriter(sourcecodeArea), 1024), imports, false);
imports.dumpHeader(writer);
clazzAna.dumpSource(writer);
writer.close();
// saveButton.setEnabled(true);
} catch (Throwable t) {
sourcecodeArea.setText("Didn't succeed.\n"
+"Check the below area for more info.");
t.printStackTrace(GlobalOptions.err);
} finally {
synchronized(this) {
decompileThread = null;
// startButton.setEnabled(true);
}
}
}
public void addMenu(JFrame frame) {
JMenuBar bar = new JMenuBar();
JMenu menu;
JMenuItem item;
menu = new JMenu("File");
item = new JMenuItem("Garbage collect");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
System.gc();
System.runFinalization();
}
});
menu.add(item);
item = new JMenuItem("Exit");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
System.exit(0);
}
});
menu.add(item);
bar.add(menu);
menu = new JMenu("Options");
final JCheckBoxMenuItem hierItem
= new JCheckBoxMenuItem("Class hierarchy", hierarchyTree);
hierItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
hierarchyTree = hierItem.isSelected();
if (hierarchyTree && hierModel == null) {
hierModel = new HierarchyTreeModel(Main.this, progressBar);
reselect();
}
classTree.setModel(hierarchyTree
? (TreeModel) hierModel : packModel);
if (lastClassName != null) {
TreePath lastPath = (hierarchyTree
? hierModel.getPath(lastClassName)
: packModel.getPath(lastClassName));
classTree.setSelectionPath(lastPath);
classTree.scrollPathToVisible(lastPath);
}
}
});
menu.add(hierItem);
menu.add(new JSeparator());
item = new JMenuItem("Set classpath...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
String newClassPath = (String) JOptionPane.showInputDialog
(null, "New classpath:", null,
JOptionPane.QUESTION_MESSAGE, null,
null, currentClassPath);
if (newClassPath != null
&& !newClassPath.equals(currentClassPath))
setClasspath(newClassPath);
}
});
menu.add(item);
item = new JMenuItem("Reload classpath");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
setClasspath(currentClassPath);
}
});
menu.add(item);
bar.add(menu);
frame.setJMenuBar(bar);
}
public void setClasspath(String classpath) {
if (classpath == null || classpath.length() == 0)
classpath = ".";
currentClassPath = classpath;
ClassInfo.setClassPath(classpath);
if (classTree != null)
classTree.clearSelection();
if (packModel != null)
packModel.rebuild();
if (hierModel != null && hierarchyTree) {
hierModel.rebuild();
} else {
hierModel = null;
}
}
public void treeNodesChanged(TreeModelEvent e) {
reselect();
}
public void treeNodesInserted(TreeModelEvent e) {
reselect();
}
public void treeNodesRemoved(TreeModelEvent e) {
reselect();
}
public void treeStructureChanged(TreeModelEvent e) {
reselect();
}
public void reselect() {
if (lastClassName != null) {
TreePath lastPath = (hierarchyTree
? hierModel.getPath(lastClassName)
: packModel.getPath(lastClassName));
if (lastPath != null) {
classTree.setSelectionPath(lastPath);
classTree.scrollPathToVisible(lastPath);
}
}
}
public static void main(String[] params) {
String cp = System.getProperty("java.class.path", "");
cp = cp.replace(File.pathSeparatorChar, SearchPath.pathSeparatorChar);
for (int i=0; i<params.length; i++) {
if (params[i].equals("--classpath"))
cp = params[++i];
else
return;
}
GlobalOptions.verboseLevel = 1;
Main win = new Main(cp);
win.show();
}
}

@ -1,30 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir)
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \
Main.java \
HierarchyTreeModel.java \
PackagesTreeModel.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include $(MY_JAVA_FILES:.java=.dep)
%.class: %.java
$(JAVAC) -classpath `$(SUBSTCP) $(BUILD_CLASSPATH):$(CLASSLIB)` -d $(top_builddir) $<
%.dep: %.class
$(JAVADEP) $< >$@
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,208 +0,0 @@
/* PackagesTreeModel Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.swingui;
import jode.Decompiler;
import jode.bytecode.ClassInfo;
import @JAVAX_SWING@.tree.TreeModel;
import @JAVAX_SWING@.tree.TreePath;
import @JAVAX_SWING@.event.TreeModelListener;
import @JAVAX_SWING@.event.TreeModelEvent;
import @COLLECTIONEXTRA@.Comparable;
import @COLLECTIONS@.Arrays;
import @COLLECTIONS@.TreeSet;
import @COLLECTIONS@.HashSet;
import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Map;
import java.util.Enumeration;
import java.util.NoSuchElementException;
public class PackagesTreeModel implements TreeModel {
Map cachedChildrens = new HashMap();
Main main;
class TreeElement implements Comparable {
String fullName;
String name;
boolean leaf;
public TreeElement(String prefix, String name, boolean isLeaf) {
this.fullName = prefix+name;
this.name = name;
this.leaf = isLeaf;
}
public String getFullName() {
return fullName;
}
public String getName() {
return name;
}
public boolean isLeaf() {
return leaf;
}
public String toString() {
return name;
}
public int compareTo(Object o) {
TreeElement other = (TreeElement) o;
if (leaf != other.leaf)
// files come after directories
return leaf ? 1 : -1;
return fullName.compareTo(other.fullName);
}
public boolean equals(Object o) {
return (o instanceof TreeElement)
&& fullName.equals(((TreeElement)o).fullName);
}
public int hashCode() {
return fullName.hashCode();
}
}
TreeElement root = new TreeElement("", "", false);
Set listeners = new HashSet();
public PackagesTreeModel(Main main) {
this.main = main;
}
public void rebuild() {
cachedChildrens.clear();
TreeModelListener[] ls;
synchronized (listeners) {
ls = (TreeModelListener[])
listeners.toArray(new TreeModelListener[listeners.size()]);
}
TreeModelEvent ev = new TreeModelEvent(this, new Object[] { root });
for (int i=0; i< ls.length; i++)
ls[i].treeStructureChanged(ev);
main.reselect();
}
public TreeElement[] getChildrens(TreeElement parent) {
TreeElement[] result =
(TreeElement[]) cachedChildrens.get(parent);
if (result == null) {
TreeSet v = new TreeSet();
String prefix = parent == root ? "" : parent.getFullName() + ".";
Enumeration enum =
ClassInfo.getClassesAndPackages(parent.getFullName());
while (enum.hasMoreElements()) {
//insert sorted and remove double elements;
String name = (String)enum.nextElement();
String fqn = prefix + name;
boolean isClass = !ClassInfo.isPackage(fqn);
if (isClass && Decompiler.skipClass(ClassInfo.forName(fqn)))
continue;
TreeElement newElem = new TreeElement(prefix, name, isClass);
v.add(newElem);
}
result = (TreeElement[]) v.toArray(new TreeElement[v.size()]);
cachedChildrens.put(parent, result);
}
return result;
}
public void addTreeModelListener(TreeModelListener l) {
listeners.add(l);
}
public void removeTreeModelListener(TreeModelListener l) {
listeners.remove(l);
}
public void valueForPathChanged(TreePath path, Object newValue) {
// we don't allow values
}
public Object getChild(Object parent, int index) {
return getChildrens((TreeElement) parent)[index];
}
public int getChildCount(Object parent) {
return getChildrens((TreeElement) parent).length;
}
public int getIndexOfChild(Object parent, Object child) {
TreeElement[] childrens = getChildrens((TreeElement) parent);
int i = Arrays.binarySearch(childrens, child);
if (i >= 0)
return i;
throw new NoSuchElementException
(((TreeElement)parent).getFullName() + "." + child);
}
public Object getRoot() {
return root;
}
public boolean isLeaf(Object node) {
return ((TreeElement) node).isLeaf();
}
public boolean isValidClass(Object node) {
return ((TreeElement) node).isLeaf();
}
public TreePath getPath(String fullName) {
if (fullName == null || fullName.length() == 0)
return new TreePath(root);
int pos = -1;
int length = 2;
while ((pos = fullName.indexOf('.', pos+1)) != -1)
length++;
TreeElement[] path = new TreeElement[length];
path[0] = root;
int i = 0;
pos = -1;
next_component:
while (pos < fullName.length()) {
int start = pos+1;
pos = fullName.indexOf('.', start);
if (pos == -1)
pos = fullName.length();
String component = fullName.substring(start, pos);
TreeElement[] childs = getChildrens(path[i]);
for (int j=0; j< childs.length; j++) {
if (childs[j].getName().equals(component)) {
path[++i] = childs[j];
continue next_component;
}
}
return null;
}
return new TreePath(path);
}
public String getFullName(Object node) {
return ((TreeElement) node).getFullName();
}
}

@ -1,2 +0,0 @@
Makefile
Makefile.in

@ -1,251 +0,0 @@
/* ArrayType Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.bytecode.ClassInfo;
import java.util.Vector;
/**
* This type represents an array type.
*
* @author Jochen Hoenicke
*/
public class ArrayType extends ReferenceType {
// The interfaces that an array implements:
final static ClassInfo[] arrayIfaces = {
// Make sure to list all interfaces, even if some interface
// implements another (or change code in getGeneralizedType().
ClassInfo.forName("java.lang.Cloneable"),
ClassInfo.forName("java.io.Serializable")
};
Type elementType;
ArrayType(Type elementType) {
super(TC_ARRAY);
this.elementType = elementType;
}
public Type getElementType() {
return elementType;
}
public Type getSuperType() {
return tRange(tObject,
(ReferenceType) tArray(elementType.getSuperType()));
}
public Type getSubType() {
return tArray(elementType.getSubType());
}
public Type getHint() {
return tArray(elementType.getHint());
}
public Type getCanonic() {
return tArray(elementType.getCanonic());
}
/**
* Create the type corresponding to the range from bottomType to this.
* @param bottomType the start point of the range
* @return the range type, or tError if not possible.
*/
public Type createRangeType(ReferenceType bottom) {
/*
* tArray(y), tArray(x) -> tArray( y.intersection(x) )
* obj , tArray(x) -> <obj, tArray(x)>
* iff tArray extends and implements obj
*/
if (bottom.getTypeCode() == TC_ARRAY)
return tArray(elementType.intersection
(((ArrayType)bottom).elementType));
if (bottom.getTypeCode() == TC_CLASS) {
ClassInterfacesType bottomCIT = (ClassInterfacesType)bottom;
if (bottomCIT.clazz == null
&& implementsAllIfaces(null, arrayIfaces, bottomCIT.ifaces))
return tRange(bottomCIT, this);
}
return tError;
}
/**
* Returns the common sub type of this and type.
* @param type the other type.
* @return the common sub type.
*/
public Type getSpecializedType(Type type) {
/*
* tArray(x), object -> tArray(x) iff tArray implements object
* tArray(x), tArray(y) -> tArray(x.intersection(y))
* tArray(x), other -> tError
*/
if (type.getTypeCode() == TC_RANGE) {
type = ((RangeType) type).getBottom();
}
if (type == tNull)
return this;
if (type.getTypeCode() == TC_ARRAY) {
return tArray(elementType.intersection
(((ArrayType)type).elementType));
}
if (type.getTypeCode() == TC_CLASS) {
ClassInterfacesType other = (ClassInterfacesType) type;
if (other.clazz == null
&& implementsAllIfaces(null, arrayIfaces, other.ifaces))
return this;
}
return tError;
}
/**
* Returns the common super type of this and type.
* @param type the other type.
* @return the common super type.
*/
public Type getGeneralizedType(Type type) {
/* tArray(x), tNull -> tArray(x)
* tArray(x), tClass(y) -> common ifaces of tArray and tClass
* tArray(x), tArray(y) -> tArray(x.intersection(y))
* tArray(x), other -> tError
*/
if (type.getTypeCode() == TC_RANGE) {
type = ((RangeType) type).getTop();
}
if (type == tNull)
return this;
if (type.getTypeCode() == TC_ARRAY)
return tArray(elementType.intersection
(((ArrayType)type).elementType));
if (type.getTypeCode() == TC_CLASS) {
ClassInterfacesType other = (ClassInterfacesType) type;
if (implementsAllIfaces(other.clazz, other.ifaces, arrayIfaces))
return ClassInterfacesType.create(null, arrayIfaces);
if (other.clazz == null
&& implementsAllIfaces(null, arrayIfaces, other.ifaces))
return other;
/* Now the more complicated part: find all interfaces, that are
* implemented by one interface or class in each group.
*
* First get all interfaces of this.clazz and this.ifaces.
*/
Vector newIfaces = new Vector();
iface_loop:
for (int i=0; i < arrayIfaces.length; i++) {
/* Now consider each array interface. If any clazz or
* interface in other implements it, add it to the
* newIfaces vector. */
if (other.clazz != null
&& arrayIfaces[i].implementedBy(other.clazz)) {
newIfaces.addElement(arrayIfaces[i]);
continue iface_loop;
}
for (int j=0; j<other.ifaces.length; j++) {
if (arrayIfaces[i].implementedBy(other.ifaces[j])) {
newIfaces.addElement(arrayIfaces[i]);
continue iface_loop;
}
}
}
ClassInfo[] ifaceArray = new ClassInfo[newIfaces.size()];
newIfaces.copyInto(ifaceArray);
return ClassInterfacesType.create(null, ifaceArray);
}
return tError;
}
/**
* Checks if we need to cast to a middle type, before we can cast from
* fromType to this type.
* @return the middle type, or null if it is not necessary.
*/
public Type getCastHelper(Type fromType) {
Type hintType = fromType.getHint();
switch (hintType.getTypeCode()) {
case TC_ARRAY:
if (!elementType.isClassType()
|| !((ArrayType)hintType).elementType.isClassType())
return tObject;
Type middleType = elementType.getCastHelper
(((ArrayType)hintType).elementType);
if (middleType != null)
return tArray(middleType);
return null;
case TC_CLASS:
ClassInterfacesType hint = (ClassInterfacesType) hintType;
if (hint.clazz == null
&& implementsAllIfaces(null, arrayIfaces, hint.ifaces))
return null;
return tObject;
case TC_UNKNOWN:
return null;
}
return tObject;
}
/**
* Checks if this type represents a valid type instead of a list
* of minimum types.
*/
public boolean isValidType() {
return elementType.isValidType();
}
public boolean isClassType() {
return true;
}
public String getTypeSignature() {
return "["+elementType.getTypeSignature();
}
public Class getTypeClass() throws ClassNotFoundException {
return Class.forName("["+elementType.getTypeSignature());
}
public String toString() {
return elementType.toString()+"[]";
}
private static String pluralize(String singular) {
return singular +
((singular.endsWith("s") || singular.endsWith("x")
|| singular.endsWith("sh") || singular.endsWith("ch"))
? "es" : "s");
}
public String getDefaultName() {
if (elementType instanceof ArrayType)
return elementType.getDefaultName();
return pluralize(elementType.getDefaultName());
}
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof ArrayType) {
ArrayType type = (ArrayType) o;
return type.elementType.equals(elementType);
}
return false;
}
}

@ -1,560 +0,0 @@
/* ClassInterfacesType Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.bytecode.ClassInfo;
import java.util.Vector;
import java.util.Stack;
/**
* This class represents a type aproximation, consisting of multiple
* interfaces and a class type.<p>
*
* If this is the bottom boundary, this specifies, which class our
* type must extend and which interfaces it must implement.
*
* If this is the top boundary, this gives all interfaces and classes
* that may extend the type. I.e. at least one interface or class extends
* the searched type.
*
* @author Jochen Hoenicke */
public class ClassInterfacesType extends ReferenceType {
ClassInfo clazz;
ClassInfo ifaces[];
public ClassInfo getClazz() {
return clazz != null ? clazz : ClassInfo.javaLangObject;
}
public ClassInterfacesType(String clazzName) {
super(TC_CLASS);
ClassInfo clazz = ClassInfo.forName(clazzName);
if (clazz.isInterface()) {
this.clazz = null;
ifaces = new ClassInfo[] {clazz};
} else {
this.clazz =
(clazz == ClassInfo.javaLangObject) ? null : clazz;
ifaces = new ClassInfo[0];
}
}
public ClassInterfacesType(ClassInfo clazz) {
super(TC_CLASS);
if (clazz.isInterface()) {
this.clazz = null;
ifaces = new ClassInfo[] { clazz };
} else {
this.clazz =
(clazz == ClassInfo.javaLangObject) ? null : clazz;
ifaces = new ClassInfo[0];
}
}
public ClassInterfacesType(ClassInfo clazz, ClassInfo[] ifaces) {
super(TC_CLASS);
this.clazz = clazz;
this.ifaces = ifaces;
}
static ClassInterfacesType create(ClassInfo clazz, ClassInfo[] ifaces) {
/* Make sure that every {java.lang.Object} equals tObject */
if (ifaces.length == 0 && clazz == null)
return tObject;
if (ifaces.length == 0)
return tClass(clazz);
if (ifaces.length == 1 && clazz == null)
return tClass(ifaces[0]);
return new ClassInterfacesType(clazz, ifaces);
}
public Type getSubType() {
if ((clazz == null && ifaces.length == 1)
|| ifaces.length == 0)
return tRange(this, tNull);
/* We don't implement the set of types, that are castable to some
* of the given classes or interfaces.
*/
throw new jode.AssertError
("getSubType called on set of classes and interfaces!");
}
public Type getHint() {
if (ifaces.length == 0
|| (clazz == null && ifaces.length == 1))
return this;
if (clazz != null)
return Type.tClass(clazz.getName());
else
return Type.tClass(ifaces[0].getName());
}
public Type getCanonic() {
if (ifaces.length == 0
|| (clazz == null && ifaces.length == 1))
return this;
if (clazz != null)
return Type.tClass(clazz.getName());
else
return Type.tClass(ifaces[0].getName());
}
/**
* Create the type corresponding to the range from bottomType to
* this. Checks if the given type range may be not empty. This
* means, that bottom.clazz is extended by this.clazz and that all
* interfaces in bottom are implemented by an interface or by
* clazz.
* @param bottom the start point of the range
* @return the range type, or tError if range is empty.
*/
public Type createRangeType(ReferenceType bottomType) {
if (bottomType.typecode != TC_CLASS)
return tError;
ClassInterfacesType bottom = (ClassInterfacesType) bottomType;
if (bottomType == tObject)
return (this == tObject) ? tObject : tRange(tObject, this);
if (bottom.clazz != null) {
/* The searched type must be a class type.
*/
if (!bottom.clazz.superClassOf(this.clazz))
return tError;
/* All interfaces must be implemented by this.clazz
*/
for (int i=0; i < bottom.ifaces.length; i++) {
if (!bottom.ifaces[i].implementedBy(this.clazz))
return tError;
}
if (bottom.clazz == this.clazz
&& bottom.ifaces.length == 0)
return bottom;
if (this.ifaces.length != 0)
return tRange(bottom, create(this.clazz, new ClassInfo[0]));
return tRange(bottom, this);
} else {
/* Now bottom.clazz is null (or tObject), find all
* classes/interfaces that implement all bottom.ifaces.
*/
ClassInfo clazz = this.clazz;
if (clazz != null) {
for (int i=0; i < bottom.ifaces.length; i++) {
if (!bottom.ifaces[i].implementedBy(clazz)) {
clazz = null;
break;
}
}
}
/* If bottom is a single interface and equals some top
* interface, then bottom is the only possible type.
*/
if (clazz == null && bottom.ifaces.length == 1) {
for (int i=0; i< this.ifaces.length; i++) {
if (this.ifaces[i] == bottom.ifaces[0])
return bottom;
}
}
ClassInfo[] ifaces = new ClassInfo[this.ifaces.length];
int count = 0;
big_loop:
for (int j=0; j < this.ifaces.length; j++) {
for (int i=0; i < bottom.ifaces.length; i++) {
if (!bottom.ifaces[i].implementedBy(this.ifaces[j]))
continue big_loop;
}
ifaces[count++] = (this.ifaces[j]);
}
if (clazz == null && count == 0) {
/* There are no more possible interfaces or classes left.
* This is a type error.
*/
return tError;
} else if (count < ifaces.length) {
ClassInfo[] shortIfaces = new ClassInfo[count];
System.arraycopy(ifaces, 0, shortIfaces, 0, count);
ifaces = shortIfaces;
} else if (clazz == this.clazz)
return tRange(bottom, this);
return tRange(bottom, create(clazz, ifaces));
}
}
/**
* Returns the specialized type of this and type.
* We have two classes and multiple interfaces. The result
* should be the object that extends both objects
* and the union of all interfaces.
*/
public Type getSpecializedType(Type type) {
int code = type.typecode;
if (code == TC_RANGE) {
type = ((RangeType) type).getBottom();
code = type.typecode;
}
if (code == TC_NULL)
return this;
if (code == TC_ARRAY)
return ((ArrayType) type).getSpecializedType(this);
if (code != TC_CLASS)
return tError;
ClassInterfacesType other = (ClassInterfacesType) type;
ClassInfo clazz;
/* First determine the clazz, one of the two classes must be a sub
* class of the other or null.
*/
if (this.clazz == null)
clazz = other.clazz;
else if (other.clazz == null)
clazz = this.clazz;
else if (this.clazz.superClassOf(other.clazz))
clazz = other.clazz;
else if (other.clazz.superClassOf(this.clazz))
clazz = this.clazz;
else
return tError;
/* Most times (99.9999999 %) one of the two classes is already
* more specialized. Optimize for this case. (I know of one
* class where at one intersection this doesn't succeed)
*/
if (clazz == this.clazz
&& implementsAllIfaces(this.clazz, this.ifaces, other.ifaces))
return this;
else if (clazz == other.clazz
&& implementsAllIfaces(other.clazz, other.ifaces,
this.ifaces))
return other;
/* The interfaces are simply the union of both interfaces set.
* But we can simplify this, if an interface is implemented by
* another or by the class, we can omit it.
*/
Vector ifaces = new Vector();
big_loop_this:
for (int i=0; i< this.ifaces.length; i++) {
ClassInfo iface = this.ifaces[i];
if (clazz != null && iface.implementedBy(clazz)) {
continue big_loop_this;
}
for (int j=0; j<other.ifaces.length; j++) {
if (iface.implementedBy(other.ifaces[j])) {
continue big_loop_this;
}
}
/* This interface is not implemented by any of the other
* ifaces. Add it to the interfaces vector.
*/
ifaces.addElement(iface);
}
big_loop_other:
for (int i=0; i< other.ifaces.length; i++) {
ClassInfo iface = other.ifaces[i];
if (clazz != null && iface.implementedBy(clazz)) {
continue big_loop_other;
}
for (int j=0; j<ifaces.size(); j++) {
if (iface.implementedBy((ClassInfo)
ifaces.elementAt(j))) {
continue big_loop_other;
}
}
/* This interface is not implemented by any of the other
* ifaces. Add it to the interfaces vector.
*/
ifaces.addElement(iface);
}
ClassInfo[] ifaceArray = new ClassInfo[ifaces.size()];
ifaces.copyInto(ifaceArray);
return create(clazz, ifaceArray);
}
/**
* Returns the generalized type of this and type. We have two
* classes and multiple interfaces. The result should be the
* object that is the the super class of both objects and all
* interfaces, that one class or interface of each type
* implements. */
public Type getGeneralizedType(Type type) {
int code = type.typecode;
if (code == TC_RANGE) {
type = ((RangeType) type).getTop();
code = type.typecode;
}
if (code == TC_NULL)
return this;
if (code == TC_ARRAY)
return ((ArrayType) type).getGeneralizedType(this);
if (code != TC_CLASS)
return tError;
ClassInterfacesType other = (ClassInterfacesType) type;
ClassInfo clazz;
/* First the easy part, determine the clazz */
if (this.clazz == null || other.clazz == null)
clazz = null;
else {
clazz = this.clazz;
while(clazz != null) {
if (clazz.superClassOf(other.clazz))
break;
clazz = clazz.getSuperclass();
}
if (clazz == ClassInfo.javaLangObject)
clazz = null;
}
if (clazz == this.clazz
&& implementsAllIfaces(other.clazz, other.ifaces, this.ifaces))
return this;
else if (clazz == other.clazz
&& implementsAllIfaces(this.clazz, this.ifaces, other.ifaces))
return other;
/* Now the more complicated part: find all interfaces, that are
* implemented by one interface or class in each group.
*
* First get all interfaces of this.clazz and this.ifaces.
*/
Stack allIfaces = new Stack();
if (this.clazz != null) {
ClassInfo c = this.clazz;
while (clazz != c) {
ClassInfo clazzIfaces[] = c.getInterfaces();
for (int i=0; i<clazzIfaces.length; i++)
allIfaces.push(clazzIfaces[i]);
c = c.getSuperclass();
}
}
Vector ifaces = new Vector();
for (int i=0; i<this.ifaces.length; i++)
allIfaces.push(this.ifaces[i]);
/* Now consider each interface. If any clazz or interface
* in other implements it, add it to the ifaces vector.
* Otherwise consider all sub interfaces.
*/
iface_loop:
while (!allIfaces.isEmpty()) {
ClassInfo iface = (ClassInfo) allIfaces.pop();
if ((clazz != null && iface.implementedBy(clazz))
|| ifaces.contains(iface))
/* We can skip this, as clazz or ifaces already imply it.
*/
continue iface_loop;
if (other.clazz != null && iface.implementedBy(other.clazz)) {
ifaces.addElement(iface);
continue iface_loop;
}
for (int i=0; i<other.ifaces.length; i++) {
if (iface.implementedBy(other.ifaces[i])) {
ifaces.addElement(iface);
continue iface_loop;
}
}
/* This interface is not implemented by any of the other
* ifaces. Try its parent interfaces now.
*/
ClassInfo clazzIfaces[] = iface.getInterfaces();
for (int i=0; i<clazzIfaces.length; i++)
allIfaces.push(clazzIfaces[i]);
}
ClassInfo[] ifaceArray = new ClassInfo[ifaces.size()];
ifaces.copyInto(ifaceArray);
return create(clazz, ifaceArray);
}
public String getTypeSignature() {
if (clazz != null)
return "L" + clazz.getName().replace('.','/') + ";";
else if (ifaces.length > 0)
return "L" + ifaces[0].getName().replace('.','/') + ";";
else
return "Ljava/lang/Object;";
}
public Class getTypeClass() throws ClassNotFoundException {
if (clazz != null)
return Class.forName(clazz.getName());
else if (ifaces.length > 0)
return Class.forName(ifaces[0].getName());
else
return Class.forName("java.lang.Object");
}
public ClassInfo getClassInfo() {
if (clazz != null)
return clazz;
else if (ifaces.length > 0)
return ifaces[0];
else
return ClassInfo.javaLangObject;
}
public String toString()
{
if (this == tObject)
return "java.lang.Object";
if (ifaces.length == 0)
return clazz.getName();
if (clazz == null && ifaces.length == 1)
return ifaces[0].getName();
StringBuffer sb = new StringBuffer("{");
String comma = "";
if (clazz != null) {
sb = sb.append(clazz.getName());
comma = ", ";
}
for (int i=0; i< ifaces.length; i++) {
sb.append(comma).append(ifaces[i].getName());
comma = ", ";
}
return sb.append("}").toString();
}
/**
* Checks if we need to cast to a middle type, before we can cast from
* fromType to this type.
* @return the middle type, or null if it is not necessary.
*/
public Type getCastHelper(Type fromType) {
Type hintType = fromType.getHint();
switch (hintType.getTypeCode()) {
case TC_ARRAY:
if (clazz == null
&& implementsAllIfaces(null, ArrayType.arrayIfaces,
this.ifaces))
return null;
else
return tObject;
case TC_CLASS:
ClassInterfacesType hint = (ClassInterfacesType) hintType;
if (hint.clazz == null || clazz == null
|| clazz.superClassOf(hint.clazz)
|| hint.clazz.superClassOf(clazz))
return null;
ClassInfo superClazz = clazz.getSuperclass();
while (superClazz != null
&& !superClazz.superClassOf(hint.clazz)) {
superClazz = superClazz.getSuperclass();
}
return tClass(superClazz.getName());
case TC_UNKNOWN:
return null;
}
return tObject;
}
/**
* Checks if this type represents a valid type instead of a list
* of minimum types.
*/
public boolean isValidType() {
return ifaces.length == 0
|| (clazz == null && ifaces.length == 1);
}
/**
* Checks if this is a class or array type (but not a null type).
* @XXX remove this?
* @return true if this is a class or array type.
*/
public boolean isClassType() {
return true;
}
/**
* Generates the default name, that is the `natural' choice for
* local of this type.
* @return the default name of a local of this type.
*/
public String getDefaultName() {
ClassInfo type;
if (clazz != null)
type = clazz;
else if (ifaces.length > 0)
type = ifaces[0];
else
type = ClassInfo.javaLangObject;
String name = type.getName();
int dot = Math.max(name.lastIndexOf('.'), name.lastIndexOf('$'));
if (dot >= 0)
name = name.substring(dot+1);
if (Character.isUpperCase(name.charAt(0)))
return name.toLowerCase();
else
return name+"_var";
}
public int hashCode() {
int hash = clazz == null ? 0 : clazz.hashCode();
for (int i=0; i < ifaces.length; i++) {
hash ^= ifaces[i].hashCode();
}
return hash;
}
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Type && ((Type)o).typecode == TC_CLASS) {
ClassInterfacesType type = (ClassInterfacesType) o;
if (type.clazz == clazz
&& type.ifaces.length == ifaces.length) {
big_loop:
for (int i=0; i< type.ifaces.length; i++) {
for (int j=0; j<ifaces.length; j++) {
if (type.ifaces[i] == ifaces[j])
continue big_loop;
}
return false;
}
return true;
}
}
return false;
}
}

@ -1,279 +0,0 @@
/* IntegerType Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.GlobalOptions;
/**
* This is a type class for 16 bit integral types. There are seven
* different types, namely <code>int, char, short, byte, boolean,
* const short, const byte</code> abbreviated <code>I, C, S, B, Z, cS,
* cB</code>. <code>cB</code> and <code>cS</code> specify constant
* ints whose value is in byte resp. short range. They may be
* converted to B resp. S, but sometimes need an explicit cast.
*
* @author Jochen Hoenicke
*/
public class IntegerType extends Type {
/* Order does matter:
* First type that is possible (and hinted) will be taken.
*/
public static final int IT_Z = 0x01;
public static final int IT_I = 0x02;
public static final int IT_C = 0x04;
public static final int IT_S = 0x08;
public static final int IT_B = 0x10;
public static final int IT_cS = 0x20;
public static final int IT_cB = 0x40;
private static final int NUM_TYPES = 7;
private static final int[] subTypes = {
/*Z*/ IT_Z,
/*I*/ IT_I|IT_C|IT_S|IT_B/*|IT_cS|IT_cB*/, /*C*/ IT_C,
/*S*/ IT_S|IT_B/*|IT_cS|IT_cB*/, /*B*/ IT_B/*|IT_cB*/,
/*cS*/IT_cS|IT_cB, /*cB*/IT_cB
};
private static final int[] superTypes = {
/*Z*/ IT_Z,
/*I*/ IT_I, /*C*/ IT_I|IT_C,
/*S*/ IT_I|IT_S, /*B*/ IT_I|IT_S|IT_B,
/*cS*/IT_I|IT_C|IT_S|IT_cS, /*cB*/IT_I|IT_C|IT_S|IT_B|IT_cS|IT_cB
};
private static final Type[] simpleTypes = {
new IntegerType(IT_Z),
new IntegerType(IT_I), new IntegerType(IT_C),
new IntegerType(IT_S), new IntegerType(IT_B),
new IntegerType(IT_cS), new IntegerType(IT_cB)
};
private static final String[] typeNames = {
"Z","I","C","S","B","s","b"
};
int possTypes;
int hintTypes;
/**
* Create a new type with the given type.
*/
public IntegerType(int types) {
this(types, types);
}
public IntegerType(int types, int hints) {
super(TC_INTEGER);
possTypes = types;
hintTypes = hints;
}
public Type getHint() {
int hint = possTypes & hintTypes;
if (hint == 0)
hint = possTypes;
int i = 0;
while ((hint & 1) == 0) {
hint >>= 1;
i++;
}
return simpleTypes[i];
}
public Type getCanonic() {
int types = possTypes;
int i = 0;
while ((types >>= 1) != 0) {
i++;
}
return simpleTypes[i];
}
private static int getSubTypes(int types) {
int result = 0;
for (int i=0; i < NUM_TYPES; i++) {
if (((1<<i) & types) != 0)
result |= subTypes[i];
}
return result;
}
private static int getSuperTypes(int types) {
int result = 0;
for (int i=0; i < NUM_TYPES; i++) {
if (((1<<i) & types) != 0)
result |= superTypes[i];
}
return result;
}
public Type getSubType() {
return new IntegerType(getSubTypes(possTypes),
getSubTypes(hintTypes));
}
public Type getSuperType() {
/* Don't upgrade hints */
return new IntegerType(getSuperTypes(possTypes), hintTypes);
}
/**
* Checks if this type represents a valid type instead of a list
* of minimum types.
*/
public boolean isValidType() {
return true;
}
/**
* Check if this and &lt;unknown -- type&rt; are not disjunct.
* @param type a simple type; this mustn't be a range type.
* @return true if this is the case.
*/
public boolean isOfType(Type type) {
return (type.typecode == TC_INTEGER
&& (((IntegerType)type).possTypes & possTypes) != 0);
}
public String getDefaultName() {
switch (((IntegerType)getHint()).possTypes) {
case IT_Z:
return "bool";
case IT_C:
return "c";
case IT_B:
case IT_S:
case IT_I:
return "i";
default:
throw new jode.AssertError("Local can't be of constant type!");
}
}
public Object getDefaultValue() {
return new Integer(0);
}
public String getTypeSignature() {
switch (((IntegerType)getHint()).possTypes) {
case IT_Z:
return "Z";
case IT_C:
return "C";
case IT_B:
return "B";
case IT_S:
return "S";
case IT_I:
default:
return "I";
}
}
public Class getTypeClass() {
switch (((IntegerType)getHint()).possTypes) {
case IT_Z:
return Boolean.TYPE;
case IT_C:
return Character.TYPE;
case IT_B:
return Byte.TYPE;
case IT_S:
return Short.TYPE;
case IT_I:
default:
return Integer.TYPE;
}
}
public String toString() {
if (possTypes == hintTypes) {
switch (possTypes) {
case IT_Z:
return "boolean";
case IT_C:
return "char";
case IT_B:
return "byte";
case IT_S:
return "short";
case IT_I:
return "int";
}
}
StringBuffer sb = new StringBuffer("{");
for (int i=0; i< NUM_TYPES; i++) {
if (((1<<i) & possTypes) != 0)
sb.append(typeNames[i]);
}
if (possTypes != hintTypes) {
sb.append(":");
for (int i=0; i< NUM_TYPES; i++) {
if (((1<<i) & hintTypes) != 0)
sb.append(typeNames[i]);
}
}
sb.append("}");
return sb.toString();
}
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (type == tError)
return type;
if (type == tUnknown)
return this;
int mergeTypes;
int mergeHints = 0;
if (type.typecode != TC_INTEGER)
mergeTypes = 0;
else {
IntegerType other = (IntegerType) type;
mergeTypes = possTypes & other.possTypes;
mergeHints = hintTypes & other.hintTypes;
if (mergeTypes == possTypes
&& mergeHints == hintTypes)
return this;
if (mergeTypes == other.possTypes
&& mergeHints == other.hintTypes)
return other;
}
Type result = mergeTypes == 0
? tError : new IntegerType(mergeTypes, mergeHints);
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0) {
GlobalOptions.err.println("intersecting "+ this +" and "+ type +
" to " + result);
}
return result;
}
public boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof IntegerType) {
IntegerType other = (IntegerType)o;
return other.possTypes == possTypes
&& other.hintTypes == hintTypes;
}
return false;
}
}

@ -1,35 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir)
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \
ArrayType.java \
ClassInterfacesType.java \
IntegerType.java \
MethodType.java \
NullType.java \
RangeType.java \
ReferenceType.java \
Type.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include $(MY_JAVA_FILES:.java=.dep)
%.class: %.java
$(JAVAC) -classpath `$(SUBSTCP) $(BUILD_CLASSPATH):$(CLASSLIB)` -d $(top_builddir) $<
%.dep: %.class
$(JAVADEP) $< >$@
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,100 +0,0 @@
/* MethodType Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
/**
* This type represents an method type.
*
* @author Jochen Hoenicke
*/
public class MethodType extends Type {
final String signature;
final Type[] parameterTypes;
final Type returnType;
public MethodType(String signature) {
super(TC_METHOD);
this.signature = signature;
int index = 1, types = 0;
while (signature.charAt(index) != ')') {
types++;
while (signature.charAt(index) == '[')
index++;
if (signature.charAt(index) == 'L')
index = signature.indexOf(';', index);
index++;
}
parameterTypes = new Type[types];
index = 1;
types = 0;
while (signature.charAt(index) != ')') {
int lastindex = index;
while (signature.charAt(index) == '[')
index++;
if (signature.charAt(index) == 'L')
index = signature.indexOf(';', index);
index++;
parameterTypes[types++]
= Type.tType(signature.substring(lastindex,index));
}
returnType = Type.tType(signature.substring(index+1));
}
public final int stackSize() {
int size = returnType.stackSize();
for (int i=0; i<parameterTypes.length; i++)
size -= parameterTypes[i].stackSize();
return size;
}
public Type[] getParameterTypes() {
return parameterTypes;
}
public Class[] getParameterClasses() throws ClassNotFoundException {
Class[] paramClasses = new Class[parameterTypes.length];
for (int i = paramClasses.length; --i >= 0; )
paramClasses[i] = parameterTypes[i].getTypeClass();
return paramClasses;
}
public Type getReturnType() {
return returnType;
}
public Class getReturnClass() throws ClassNotFoundException {
return returnType.getTypeClass();
}
public String getTypeSignature() {
return signature;
}
public String toString() {
return signature;
}
public boolean equals(Object o) {
MethodType mt;
return (o instanceof MethodType
&& signature.equals((mt = (MethodType)o).signature));
}
}

@ -1,85 +0,0 @@
/* NullType Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.AssertError;
/**
* This class represents the NullType. The null type is special as it
* may only occur as top type in a range type. It represents the type
* of the null constant, which may be casted to any object. <br>
*
* Question: Should we replace tUObject = tRange(tObject, tNull) by tNull?
* Question2: if not, should null have type tNull?
*
* @author Jochen Hoenicke
*/
public class NullType extends ReferenceType {
public NullType() {
super(TC_NULL);
}
public Type getSubType() {
return this;
}
public Type createRangeType(ReferenceType bottomType) {
return tRange(bottomType, this);
}
/**
* Returns the generalized type of this and type. We have two
* classes and multiple interfaces. The result should be the
* object that is the the super class of both objects and all
* interfaces, that one class or interface of each type
* implements.
*/
public Type getGeneralizedType(Type type) {
if (type.typecode == TC_RANGE)
type = ((RangeType) type).getTop();
return type;
}
/**
* Returns the specialized type of this and type.
* We have two classes and multiple interfaces. The result
* should be the object that extends both objects
* and the union of all interfaces.
*/
public Type getSpecializedType(Type type) {
if (type.typecode == TC_RANGE)
type = ((RangeType) type).getBottom();
return type;
}
public String toString() {
return "tNull";
}
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (type == this)
return type;
return tError;
}
}

@ -1,222 +0,0 @@
/* RangeType Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.AssertError;
import jode.GlobalOptions;
import java.util.Hashtable;
/**
* This class represents a set of reference types. The set contains
* all types that are castable to all the bottom types by a widening
* cast and to which one of the top types can be casted to by a
* widening cast. <br>
*
* For a totally unknown reference type bottomType is tObject and
* topType is tNull. The bottomType is always guaranteed to be not
* tNull. And all topTypes must be castable to all bottom types with
* a widening cast. <br>
*
* To do intersection on range types, the reference types need three
* more operations: specialization, generalization and
* createRange. <p>
*
* specialization chooses all common sub type of two types. It is
* used to find the bottom of the intersected interval. <p>
*
* generalization chooses the common super type of two types. It
* is used to find the top of the intersected interval. <p>
*
* When the new interval is created with <code>createRangeType</code>
* the bottom and top are adjusted so that they only consists of
* possible types. It then decides, if it needs a range type, or if
* the reference types already represents all types.
*
* @author Jochen Hoenicke
* @see ReferenceType
* @date 98/08/06 */
public class RangeType extends Type {
/**
* The bottom type set. It is special in that its interpretation
* depends on what ReferenceType class it implements:
*
* <dl>
* <dt>ClassInterfacesType</dt>
* <dd>All types in this range must be widening castable to all interfaces
* and to the class in the bottomType</dd>
* <dt>ArrayType</dt>
* <dd>All types in this range must be of the bottomType, or the
* NullType.</dd>
* <dt>NullType</dt>
* <dd>not allowed</dd>
* </dl> */
final ReferenceType bottomType;
/**
* The top type set. For each type in this range type, there is a
* top type, that can be casted to this type.
*/
final ReferenceType topType;
/**
* Create a new range type with the given bottom and top set.
*/
public RangeType(ReferenceType bottomType,
ReferenceType topType) {
super(TC_RANGE);
if (bottomType == tNull)
throw new jode.AssertError("bottom is NULL");
this.bottomType = bottomType;
this.topType = topType;
}
/**
* Returns the bottom type set. All types in this range type can
* be casted to all bottom types by a widening cast.
* @return the bottom type set
*/
public ReferenceType getBottom() {
return bottomType;
}
/**
* Returns the top type set. For each type in this range type,
* there is a top type, that can be casted to this type.
* @return the top type set
*/
public ReferenceType getTop() {
return topType;
}
/**
* Returns the hint type of this range type set. This returns the
* singleton set containing only the first top type, except if it
* is null and there is a unique bottom type, in which case it returns
* the bottom type.
* @return the hint type.
*/
public Type getHint() {
return topType == tNull && bottomType.equals(bottomType.getHint())
? bottomType.getHint(): topType.getHint();
}
/**
* Returns the canonic type of this range type set. This returns the
* singleton set containing only the first top type.
* @return the canonic type.
*/
public Type getCanonic() {
return topType.getCanonic();
}
/**
* The set of super types of this type. This is the set of
* super types of the top type.
* @return the set of super types.
*/
public Type getSuperType() {
return topType.getSuperType();
}
/**
* The set of sub types of this type. This is the set of
* sub types of the bottom types.
* @return the set of super types.
*/
public Type getSubType() {
return tRange(bottomType, tNull);
}
/**
* Checks if we need to cast to a middle type, before we can cast from
* fromType to this type.
* @return the middle type, or null if it is not necessary.
*/
public Type getCastHelper(Type fromType) {
return topType.getCastHelper(fromType);
}
public String getTypeSignature() {
if (topType.isClassType() || !bottomType.isValidType())
return topType.getTypeSignature();
else
return bottomType.getTypeSignature();
}
public Class getTypeClass() throws ClassNotFoundException {
if (topType.isClassType() || !bottomType.isValidType())
return topType.getTypeClass();
else
return bottomType.getTypeClass();
}
public String toString()
{
return "<" + bottomType + "-" + topType + ">";
}
public String getDefaultName() {
throw new AssertError("getDefaultName() called on range");
}
public int hashCode() {
int hashcode = topType.hashCode();
return (hashcode << 16 | hashcode >>> 16) ^ bottomType.hashCode();
}
public boolean equals(Object o) {
if (o instanceof RangeType) {
RangeType type = (RangeType) o;
return topType.equals(type.topType)
&& bottomType.equals(type.bottomType);
}
return false;
}
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (type == tError)
return type;
if (type == Type.tUnknown)
return this;
Type top, bottom, result;
bottom = bottomType.getSpecializedType(type);
top = topType.getGeneralizedType(type);
if (top.equals(bottom))
result = top;
else if (top instanceof ReferenceType
&& bottom instanceof ReferenceType)
result = ((ReferenceType)top)
.createRangeType((ReferenceType)bottom);
else
result = tError;
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0) {
GlobalOptions.err.println("intersecting "+ this +" and "+ type +
" to " + result);
}
return result;
}
}

@ -1,143 +0,0 @@
/* ReferenceType Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.GlobalOptions;
import jode.bytecode.ClassInfo;
import java.util.Vector;
import java.util.Stack;
/**
* This is an abstrace super class of all reference types. Reference
* types are ClassInterfacesType, ArrayType and NullType. <p>
*
* To do intersection on range types, the reference types need three
* more operations: specialization, generalization and
* createRange. <p>
*
* specialization chooses all common sub type of two types. It is
* used to find the bottom of the intersected interval. <p>
*
* generalization chooses the common super type of two types. It
* is used to find the top of the intersected interval. <p>
*
* When the new interval is created with <code>createRangeType</code>
* the bottom and top are adjusted so that they only consists of
* possible types. It then decides, if it needs a range type, or if
* the reference types already represents all types.
*
* @author Jochen Hoenicke
*/
public abstract class ReferenceType extends Type {
public ReferenceType(int typecode) {
super(typecode);
}
/**
* Returns the specialized type set of this and type. The result
* should be a type set, so that every type, extends all types in
* type and this, iff it extends all types in the resulting type
* set.
* @param type the other type.
* @return the specialized type. */
public abstract Type getSpecializedType(Type type);
/**
* Returns the generalized type set of this and type. The result
* should be a type set, so that every type, is extended/implemented
* by one type in this and one type in <code>type</code>, iff it is
* extended/implemented by one type in the resulting type set.
* @param type the other type.
* @return the generalized type
*/
public abstract Type getGeneralizedType(Type type);
/**
* Creates a range type set of this and bottom. The resulting type set
* contains all types, that extend all types in bottom and are extended
* by at least one type in this. <br>
* Note that a RangeType will do this, but we normalize the bottom and
* top set.
* @param bottom the bottom type.
* @return the range type set.
*/
public abstract Type createRangeType(ReferenceType bottom);
/**
* Tells if all otherIfaces, are implemented by at least one
* ifaces or by clazz.
*
* This is a useful function for generalizing/specializing interface
* types or arrays.
* @param clazz The clazz, can be null.
* @param ifaces The ifaces.
* @param otherifaces The other ifaces, that must be implemented.
* @return true, if all otherIfaces are implemented.
*/
protected static boolean implementsAllIfaces(ClassInfo clazz,
ClassInfo[] ifaces,
ClassInfo[] otherIfaces) {
big:
for (int i=0; i < otherIfaces.length; i++) {
ClassInfo iface = otherIfaces[i];
if (clazz != null && iface.implementedBy(clazz))
continue big;
for (int j=0; j < ifaces.length; j++) {
if (iface.implementedBy(ifaces[j]))
continue big;
}
return false;
}
return true;
}
public Type getSuperType() {
return (this == tObject) ? tObject : tRange(tObject, this);
}
public abstract Type getSubType();
/**
* Intersect this type with another type and return the new type.
* @param type the other type.
* @return the intersection, or tError, if a type conflict happens.
*/
public Type intersection(Type type) {
if (type == tError)
return type;
if (type == Type.tUnknown)
return this;
Type newBottom = getSpecializedType(type);
Type newTop = getGeneralizedType(type);
Type result;
if (newTop.equals(newBottom))
result = newTop;
else if (newTop instanceof ReferenceType
&& newBottom instanceof ReferenceType)
result = ((ReferenceType) newTop)
.createRangeType((ReferenceType) newBottom);
else
result = tError;
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0) {
GlobalOptions.err.println("intersecting "+ this +" and "+ type +
" to " + result);
}
return result;
}
}

@ -1,555 +0,0 @@
/* Type Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.type;
import jode.AssertError;
import jode.GlobalOptions;
import jode.bytecode.ClassInfo;
import jode.util.UnifyHash;
import @COLLECTIONS@.Iterator;
/**
* This is my type class. It differs from java.lang.class, in that it
* represents a set of types. Since most times this set is infinite, it
* needs a special representation. <br>
*
* The main operation on a type sets are tSuperType, tSubType and
* intersection.
*
* @author Jochen Hoenicke */
public class Type {
public static final int TC_BOOLEAN = 0;
public static final int TC_BYTE = 1;
public static final int TC_CHAR = 2;
public static final int TC_SHORT = 3;
public static final int TC_INT = 4;
public static final int TC_LONG = 5;
public static final int TC_FLOAT = 6;
public static final int TC_DOUBLE = 7;
public static final int TC_NULL = 8;
public static final int TC_ARRAY = 9;
public static final int TC_CLASS = 10;
public static final int TC_VOID = 11;
public static final int TC_METHOD = 12;
public static final int TC_ERROR = 13;
public static final int TC_UNKNOWN = 101;
public static final int TC_RANGE = 103;
public static final int TC_INTEGER = 107;
private static final UnifyHash classHash = new UnifyHash();
private static final UnifyHash arrayHash = new UnifyHash();
private static final UnifyHash methodHash = new UnifyHash();
/**
* This type represents the singleton set containing the boolean type.
*/
public static final Type tBoolean = new IntegerType(IntegerType.IT_Z);
/**
* This type represents the singleton set containing the byte type.
*/
public static final Type tByte = new IntegerType(IntegerType.IT_B);
/**
* This type represents the singleton set containing the char type.
*/
public static final Type tChar = new IntegerType(IntegerType.IT_C);
/**
* This type represents the singleton set containing the short type.
*/
public static final Type tShort = new IntegerType(IntegerType.IT_S);
/**
* This type represents the singleton set containing the int type.
*/
public static final Type tInt = new IntegerType(IntegerType.IT_I);
/**
* This type represents the singleton set containing the long type.
*/
public static final Type tLong = new Type(TC_LONG);
/**
* This type represents the singleton set containing the float type.
*/
public static final Type tFloat = new Type(TC_FLOAT);
/**
* This type represents the singleton set containing the double type.
*/
public static final Type tDouble = new Type(TC_DOUBLE);
/**
* This type represents the void type. It is really not a type at
* all.
*/
public static final Type tVoid = new Type(TC_VOID);
/**
* This type represents the empty set, and probably means, that something
* has gone wrong.
*/
public static final Type tError = new Type(TC_ERROR);
/**
* This type represents the set of all possible types.
*/
public static final Type tUnknown = new Type(TC_UNKNOWN);
/**
* This type represents the set of all integer types, up to 32 bit.
*/
public static final Type tUInt = new IntegerType(IntegerType.IT_I
| IntegerType.IT_B
| IntegerType.IT_C
| IntegerType.IT_S);
/**
* This type represents the set of the boolean and int type.
*/
public static final Type tBoolInt = new IntegerType(IntegerType.IT_I
| IntegerType.IT_Z);
/**
* This type represents the set of boolean and all integer types,
* up to 32 bit.
*/
public static final Type tBoolUInt= new IntegerType(IntegerType.IT_I
| IntegerType.IT_B
| IntegerType.IT_C
| IntegerType.IT_S
| IntegerType.IT_Z);
/**
* This type represents the set of the boolean and byte type.
*/
public static final Type tBoolByte= new IntegerType(IntegerType.IT_B
| IntegerType.IT_Z);
/**
* This type represents the singleton set containing
* <code>java.lang.Object</code>.
*/
public static final ClassInterfacesType tObject =
tClass("java.lang.Object");
/**
* This type represents the singleton set containing the special
* null type (the type of null).
*/
public static final ReferenceType tNull = new NullType();
/**
* This type represents the set of all reference types, including
* class types, array types, interface types and the null type.
*/
public static final Type tUObject = tRange(tObject, tNull);
/**
* This type represents the singleton set containing
* <code>java.lang.String</code>.
*/
public static final Type tString = tClass("java.lang.String");
/**
* This type represents the singleton set containing
* <code>java.lang.StringBuffer</code>.
*/
public static final Type tStringBuffer = tClass("java.lang.StringBuffer");
/**
* This type represents the singleton set containing
* <code>java.lang.Class</code>.
*/
public static final Type tJavaLangClass = tClass("java.lang.Class");
/**
* Generate the singleton set of the type represented by the given
* string.
* @param type the type signature (or method signature).
* @return a singleton set containing the given type.
*/
public static final Type tType(String type) {
if (type == null || type.length() == 0)
return tError;
switch(type.charAt(0)) {
case 'Z':
return tBoolean;
case 'B':
return tByte;
case 'C':
return tChar;
case 'S':
return tShort;
case 'I':
return tInt;
case 'F':
return tFloat;
case 'J':
return tLong;
case 'D':
return tDouble;
case 'V':
return tVoid;
case '[':
return tArray(tType(type.substring(1)));
case 'L':
int index = type.indexOf(';');
if (index != type.length()-1)
return tError;
return tClass(type.substring(1, index));
case '(':
return tMethod(type);
}
throw new AssertError("Unknown type signature: "+type);
}
/**
* Generate the singleton set of the type represented by the given
* class name.
* @param clazzname the full qualified name of the class.
* The packages may be separated by `.' or `/'.
* @return a singleton set containing the given type.
*/
public static final ClassInterfacesType tClass(String clazzname) {
return tClass(ClassInfo.forName(clazzname.replace('/','.')));
}
/**
* Generate the singleton set of the type represented by the given
* class info.
* @param clazzinfo the jode.bytecode.ClassInfo.
* @return a singleton set containing the given type.
*/
public static final ClassInterfacesType tClass(ClassInfo clazzinfo) {
int hash = clazzinfo.hashCode();
Iterator iter = classHash.iterateHashCode(hash);
while (iter.hasNext()) {
ClassInterfacesType type = (ClassInterfacesType) iter.next();
if (type.getClassInfo() == clazzinfo)
return type;
}
ClassInterfacesType type = new ClassInterfacesType(clazzinfo);
classHash.put(hash, type);
return type;
}
/**
* Generate/look up the set of the array type whose element types
* are in the given type set.
* @param type the element types (which may be the empty set tError).
* @return the set of array types (which may be the empty set tError).
*/
public static final Type tArray(Type type) {
if (type == tError)
return type;
int hash = type.hashCode();
Iterator iter = arrayHash.iterateHashCode(hash);
while (iter.hasNext()) {
ArrayType arrType = (ArrayType) iter.next();
if (arrType.getElementType().equals(type))
return arrType;
}
ArrayType arrType = new ArrayType(type);
arrayHash.put(hash, arrType);
return arrType;
}
/**
* Generate/look up the method type for the given signature
* @param signature the method decriptor.
* @return a method type (a singleton set).
*/
public static MethodType tMethod(String signature) {
int hash = signature.hashCode();
Iterator iter = methodHash.iterateHashCode(hash);
while (iter.hasNext()) {
MethodType methodType = (MethodType) iter.next();
if (methodType.getTypeSignature().equals(signature))
return methodType;
}
MethodType methodType = new MethodType(signature);
methodHash.put(hash, methodType);
return methodType;
}
/**
* Generate the range type from bottom to top. This should
* represent all reference types, that can be casted to bottom by
* a widening cast and where top can be casted to. You should not
* use this method directly; use tSubType, tSuperType and
* intersection instead, which is more general.
* @param bottom the bottom type.
* @param top the top type.
* @return the range type.
*/
public static final Type tRange(ReferenceType bottom,
ReferenceType top) {
return new RangeType(bottom, top);
}
/**
* Generate the set of types, to which one of the types in type can
* be casted to by a widening cast. The following holds:
* <ul><li>tSuperType(tObject) = tObject </li>
* <li>tSuperType(tError) = tError </li>
* <li>type.intersection(tSuperType(type)).equals(type)
* (this means type is a subset of tSuperType(type).</li>
* <li>tSuperType(tNull) = tUObject</li>
* <li>tSuperType(tChar) = {tChar, tInt } </li></ul>
* @param type a set of types.
* @return the super types of type.
*/
public static Type tSuperType(Type type) {
return type.getSuperType();
}
/**
* Generate the set of types, which can be casted to one of the
* types in type by a widening cast. The following holds:
* <ul><li>tSubType(tObject) = tUObject </li>
* <li>tSubType(tError) = tError </li>
* <li>type.intersection(tSubType(type)).equals(type)
* (this means type is a subset of tSubType(type).</li>
* <li>tSuperType(tSubType(type)) is a subset of type </li>
* <li>tSubType(tSuperType(type)) is a subset of type </li>
* <li>tSubType(tNull) = tNull</li>
* <li>tSubType(tBoolean, tShort) = { tBoolean, tByte, tShort }</li></ul>
* @param type a set of types.
* @return the sub types of type.
*/
public static Type tSubType(Type type) {
return type.getSubType();
}
/**
* The typecode of this type. This should be one of the TC_ constants.
*/
final int typecode;
/**
* Create a new type with the given type code.
*/
protected Type(int tc) {
typecode = tc;
}
/**
* The sub types of this type.
* @return tSubType(this).
*/
public Type getSubType() {
return this;
}
/**
* The super types of this type.
* @return tSuperType(this).
*/
public Type getSuperType() {
return this;
}
/**
* Returns the hint type of this type set. This returns the singleton
* set containing only the `most likely' type in this set. This doesn't
* work for <code>tError</code> or <code>tUnknown</code>, and may lead
* to errors for certain range types.
* @return the hint type.
*/
public Type getHint() {
return getCanonic();
}
/**
* Returns the canonic type of this type set. The intention is, to
* return for each expression the type, that the java compiler would
* assign to this expression.
* @return the canonic type.
*/
public Type getCanonic() {
return this;
}
/**
* Returns the type code of this type. Don't use this; it is
* merily needed by the sub types (and the bytecode verifier, which
* has its own type merging methods).
* @return the type code of the type.
*/
public final int getTypeCode() {
return typecode;
}
/**
* Returns the number of stack/local entries an object of this type
* occupies.
* @return 0 for tVoid, 2 for tDouble and tLong and
* 1 for every other type.
*/
public int stackSize()
{
switch(typecode) {
case TC_VOID:
return 0;
case TC_ERROR:
default:
return 1;
case TC_DOUBLE:
case TC_LONG:
return 2;
}
}
/**
* Intersect this set of types with another type set and return the
* intersection.
* @param type the other type set.
* @return the intersection, tError, if the intersection is empty.
*/
public Type intersection(Type type) {
if (this == tError || type == tError)
return tError;
if (this == tUnknown)
return type;
if (type == tUnknown || this == type)
return this;
/* We have two different singleton sets now.
*/
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("intersecting "+ this +" and "+ type
+ " to <error>");
return tError;
}
/**
* Checks if we need to cast to a middle type, before we can cast from
* fromType to this type. For example it is impossible to cast a
* String to a StringBuffer, but if we cast to Object in between this
* is allowed (it doesn't make much sense though).
* @return the middle type, or null if it is not necessary.
*/
public Type getCastHelper(Type fromType) {
return null;
}
/**
* Checks if this type represents a valid singleton type.
*/
public boolean isValidType() {
return typecode <= TC_DOUBLE;
}
/**
* Checks if this is a class or array type (but not a null type).
* @XXX remove this?
* @return true if this is a class or array type.
*/
public boolean isClassType() {
return false;
}
/**
* Check if this type set and the other type set are not disjunct.
* @param type the other type set.
* @return true if this they aren't disjunct.
*/
public boolean isOfType(Type type) {
return this.intersection(type) != Type.tError;
}
/**
* Generates the default name, that is the `natural' choice for
* local of this type.
* @return the default name of a local of this type.
*/
public String getDefaultName() {
switch (typecode) {
case TC_LONG:
return "l";
case TC_FLOAT:
return "f";
case TC_DOUBLE:
return "d";
default:
return "local";
}
}
/**
* Generates the default value, that is the initial value of a field
* of this type.
* @return the default value of a field of this type.
*/
public Object getDefaultValue() {
switch (typecode) {
case TC_LONG:
return new Long(0);
case TC_FLOAT:
return new Float(0);
case TC_DOUBLE:
return new Double(0);
default:
return null;
}
}
/**
* Returns the type signature of this type. You should only call
* this on singleton types.
* @return the type (or method) signature of this type.
*/
public String getTypeSignature() {
switch (typecode) {
case TC_LONG:
return "J";
case TC_FLOAT:
return "F";
case TC_DOUBLE:
return "D";
default:
return "?";
}
}
/**
* Returns the java.lang.Class representing this type. You should
* only call this on singleton types.
* @return the Class object representing this type.
*/
public Class getTypeClass() throws ClassNotFoundException {
switch (typecode) {
case TC_LONG:
return Long.TYPE;
case TC_FLOAT:
return Float.TYPE;
case TC_DOUBLE:
return Double.TYPE;
default:
throw new AssertError("getTypeClass() called on illegal type");
}
}
/**
* Returns a string representation describing this type set.
* @return a string representation describing this type set.
*/
public String toString() {
switch (typecode) {
case TC_LONG:
return "long";
case TC_FLOAT:
return "float";
case TC_DOUBLE:
return "double";
case TC_NULL:
return "null";
case TC_VOID:
return "void";
case TC_UNKNOWN:
return "<unknown>";
case TC_ERROR:
default:
return "<error>";
}
}
}

@ -1,2 +0,0 @@
Makefile
Makefile.in

@ -1,38 +0,0 @@
/* ArrayEnum Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.util;
public class ArrayEnum implements java.util.Enumeration {
int index = 0;
int size;
Object[] array;
public ArrayEnum(int size, Object[] array) {
this.size = size;
this.array = array;
}
public boolean hasMoreElements() {
return index < size;
}
public Object nextElement() {
return array[index++];
}
}

@ -1,31 +0,0 @@
## Input file for automake to generate the Makefile.in used by configure
JAR = @JAR@
JAVAC = @JAVAC@
JAVADEP = $(top_builddir)/javaDependencies.pl -subdir=$(subdir)\
-dependdir=$(top_builddir) -classpath=$(top_builddir):$(top_srcdir)
CLASSPATH = @CLASSPATH@
CLASSLIB = @CLASSLIB@
SUBSTCP = @SUBSTCP@
BUILD_CLASSPATH = $(top_srcdir):$(top_builddir):$(CLASSPATH):$(CLASSLIB)
MY_JAVA_FILES = \
ArrayEnum.java \
SimpleMap.java \
SimpleSet.java \
UnifyHash.java
noinst_DATA = $(MY_JAVA_FILES:.java=.class)
EXTRA_DIST = $(MY_JAVA_FILES)
@QUOTE@-include $(MY_JAVA_FILES:.java=.dep)
%.class: %.java
$(JAVAC) -classpath `$(SUBSTCP) $(BUILD_CLASSPATH):$(CLASSLIB)` -d $(top_builddir) $<
%.dep: %.class
$(JAVADEP) $< >$@
clean-local:
@rm -f *.class
@rm -f *.dep

@ -1,98 +0,0 @@
/* SimpleMap Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.util;
import @COLLECTIONS@.AbstractMap;
import @COLLECTIONS@.Map;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.Set;
/**
* This is a very simple map, using a set as backing.
* The default backing set is a simple set, but you can specify any other
* set of Map.Entry in the constructor.
*/
public class SimpleMap extends AbstractMap {
private Set backing;
public SimpleMap() {
backing = new SimpleSet();
}
public SimpleMap(int initialCapacity) {
backing = new SimpleSet(initialCapacity);
}
public SimpleMap(Set fromSet) {
backing = fromSet;
}
public Set entrySet() {
return backing;
}
public static class SimpleEntry implements Map.Entry {
Object key;
Object value;
public SimpleEntry(Object key, Object value) {
this.key = key;
this.value = value;
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object newValue) {
Object old = value;
value = newValue;
return old;
}
public int hashCode() {
return key.hashCode() ^ value.hashCode();
}
public boolean equals(Object o) {
if (o instanceof Map.Entry) {
Map.Entry e = (Map.Entry) o;
return key.equals(e.getKey()) && value.equals(e.getValue());
}
return false;
}
}
public Object put(Object key, Object value) {
for (Iterator i = backing.iterator();
i.hasNext(); ) {
Map.Entry entry = (Map.Entry) i.next();
if (key.equals(entry.getKey()))
return entry.setValue(value);
}
backing.add(new SimpleEntry(key, value));
return null;
}
}

@ -1,90 +0,0 @@
/* SimpleSet Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.util;
import @COLLECTIONS@.AbstractSet;
import @COLLECTIONS@.Iterator;
public class SimpleSet extends AbstractSet implements Cloneable
{
Object[] elementObjects;
int count = 0;
public SimpleSet() {
this(2);
}
public SimpleSet(int initialSize) {
elementObjects = new Object[initialSize];
}
public int size() {
return count;
}
public boolean add(Object element) {
if (element == null)
throw new NullPointerException();
for (int i=0; i< count; i++) {
if (element.equals(elementObjects[i]))
return false;
}
if (count == elementObjects.length) {
Object[] newArray = new Object[(count+1)*3/2];
System.arraycopy(elementObjects,0,newArray,0,count);
elementObjects = newArray;
}
elementObjects[count++] = element;
return true;
}
public Object clone() {
try {
SimpleSet other = (SimpleSet) super.clone();
other.elementObjects = (Object[]) elementObjects.clone();
return other;
} catch (CloneNotSupportedException ex) {
throw new jode.AssertError("Clone?");
}
}
public Iterator iterator() {
return new Iterator() {
int pos = 0;
public boolean hasNext() {
return pos < count;
}
public Object next() {
return elementObjects[pos++];
}
public void remove() {
if (pos < count)
System.arraycopy(elementObjects, pos,
elementObjects, pos-1, count - pos);
count--;
pos--;
}
};
}
}

@ -1,259 +0,0 @@
/* UnifyHash Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.util;
///#ifdef JDK12
///import java.lang.ref.WeakReference;
///import java.lang.ref.ReferenceQueue;
///#endif
import @COLLECTIONS@.Comparator;
import @COLLECTIONS@.AbstractCollection;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.NoSuchElementException;
import @COLLECTIONS@.ConcurrentModificationException;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
public class UnifyHash extends AbstractCollection {
/**
* the default capacity
*/
private static final int DEFAULT_CAPACITY = 11;
/** the default load factor of a HashMap */
private static final float DEFAULT_LOAD_FACTOR = 0.75F;
///#ifdef JDK12
/// private ReferenceQueue queue = new ReferenceQueue();
///#endif
static class Bucket
///#ifdef JDK12
/// extends WeakReference
///#endif
{
///#ifdef JDK12
/// public Bucket(Object o, ReferenceQueue q) {
/// super(o, q);
/// }
///#else
public Bucket(Object o) {
this.obj = o;
}
Object obj;
public Object get() {
return obj;
}
///#endif
int hash;
Bucket next;
}
private Bucket[] buckets;
int modCount = 0;
int size = 0;
int threshold;
float loadFactor;
public UnifyHash(int initialCapacity, float loadFactor) {
this.loadFactor = loadFactor;
buckets = new Bucket[initialCapacity];
threshold = (int) (loadFactor * initialCapacity);
}
public UnifyHash(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public UnifyHash() {
this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);
}
private void grow() {
Bucket[] oldBuckets = buckets;
int newCap = buckets.length * 2 + 1;
threshold = (int) (loadFactor * newCap);
buckets = new Bucket[newCap];
for (int i = 0; i < oldBuckets.length; i++) {
Bucket nextBucket;
for (Bucket b = oldBuckets[i]; b != null; b = nextBucket) {
if (i != Math.abs(b.hash % oldBuckets.length))
throw new RuntimeException(""+i+", hash: "+b.hash+", oldlength: "+oldBuckets.length);
int newSlot = Math.abs(b.hash % newCap);
nextBucket = b.next;
b.next = buckets[newSlot];
buckets[newSlot] = b;
}
}
}
///#ifdef JDK12
/// public final void cleanUp() {
/// Bucket died;
/// while ((died = (Bucket)queue.poll()) != null) {
/// int diedSlot = Math.abs(died.hash % buckets.length);
/// if (buckets[diedSlot] == died)
/// buckets[diedSlot] = died.next;
/// else {
/// Bucket b = buckets[diedSlot]
/// while (b.next != died)
/// b = b.next;
/// b.next = died.next;
/// }
/// size--;
/// }
/// }
///#endif
public int size() {
return size;
}
public Iterator iterator() {
///#ifdef JDK12
/// cleanUp();
///#endif
return new Iterator() {
private int bucket = 0;
private int known = modCount;
private Bucket nextBucket;
private Object nextVal;
{
internalNext();
}
private void internalNext() {
while (true) {
while (nextBucket == null) {
if (bucket == buckets.length)
return;
nextBucket = buckets[bucket++];
}
nextVal = nextBucket.get();
if (nextVal != null)
return;
nextBucket = nextBucket.next;
}
}
public boolean hasNext() {
return nextBucket != null;
}
public Object next() {
if (known != modCount)
throw new ConcurrentModificationException();
if (nextBucket == null)
throw new NoSuchElementException();
Object result = nextVal;
nextBucket = nextBucket.next;
internalNext();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public Iterator iterateHashCode(final int hash) {
return new Iterator() {
private int known = modCount;
private Bucket nextBucket
= buckets[Math.abs(hash % buckets.length)];
private Object nextVal;
{
internalNext();
}
private void internalNext() {
while (nextBucket != null) {
if (nextBucket.hash == hash) {
nextVal = nextBucket.get();
if (nextVal != null)
return;
}
nextBucket = nextBucket.next;
}
}
public boolean hasNext() {
return nextBucket != null;
}
public Object next() {
if (known != modCount)
throw new ConcurrentModificationException();
if (nextBucket == null)
throw new NoSuchElementException();
Object result = nextVal;
nextBucket = nextBucket.next;
internalNext();
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public void put(int hash, Object o) {
if (size++ > threshold)
grow();
modCount++;
int slot = Math.abs(hash % buckets.length);
///#ifdef JDK12
/// Bucket b = new Bucket(o, queue);
///#else
Bucket b = new Bucket(o);
///#endif
b.hash = hash;
b.next = buckets[slot];
buckets[slot] = b;
}
public Object unify(Object o, int hash, Comparator comparator) {
///#ifdef JDK12
/// cleanUp();
///#endif
int slot = Math.abs(hash % buckets.length);
for (Bucket b = buckets[slot]; b != null; b = b.next) {
Object old = b.get();
if (old != null && comparator.compare(o, old) == 0)
return old;
}
put(hash, o);
return o;
}
}

@ -1,2 +0,0 @@
Makefile
Makefile.in

@ -1,189 +0,0 @@
/* AnonymousClass Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
import java.util.Vector;
public class AnonymousClass {
class Inner {
int var = 3;
public void test() {
final long longVar = 5;
final double dblVar = 3;
class Hello {
int var = (int) longVar;
{
System.err.println("all constructors");
}
Hello() {
System.err.println("construct");
}
Hello(String info) {
System.err.println("construct: "+info);
}
///#ifndef JAVAC11
///#ifndef JAVAC12
///#ifndef JIKES
/// Hello(int i) {
/// this("If you find a compiler that can compile this,"
/// +" please comment this out and tell me if "
/// +"decompilation works.\n"
/// +"jikes 0.47, javac 1.2 are both broken!");
/// }
///#endif
///#endif
///#endif
public void hello() {
this.hashCode();
Inner.this.hashCode();
AnonymousClass.this.hashCode();
System.err.println("HelloWorld: "+dblVar);
}
};
final Hello hi = new Hello();
final Hello ho = new Hello("ho");
final Object o = new Object() {
int blah = 5;
Hello hii = hi;
{
System.err.println("Anonymous Constructor speaking");
}
public String toString() {
this.hii.hello();
hi.hello();
return Integer.toHexString(AnonymousClass.this.hashCode()
+blah);
}
{
System.err.println("Anonymous Constructor continues");
}
};
Object p = new Object() {
public String toString() {
return o.toString();
}
};
///#ifndef JAVAC12
Hello blah = new Hello("Hello World") {
public void hello() {
System.err.println("overwritten");
}
};
///#endif
Inner blub = new AnonymousClass().new Inner("Inner param") {
public void test() {
System.err.println("overwritten");
}
};
class Hi extends Inner {
public Hi() {
super("Hi World");
}
}
Vector v = new Vector(hi.var, new Inner("blah").var) {
public String newMethod() {
return super.toString();
}
};
Hi hu = new Hi();
}
Inner (String str) {
}
}
public void test() {
class Hello {
int var = 4;
Hello() {
System.err.println("construct");
}
Hello(String info) {
System.err.println("construct: "+info);
}
public void hello() {
this.hashCode();
AnonymousClass.this.hashCode();
System.err.println("HelloWorld");
}
};
final Hello hi = new Hello();
final Hello ho = new Hello("ho");
final Object o = new Object() {
int blah = 5;
Hello hii = hi;
public String toString() {
this.hii.hello();
hi.hello();
return Integer.toHexString(AnonymousClass.this.hashCode()
+blah);
}
};
Object p = new Object() {
public String toString() {
return o.toString();
}
};
///#ifndef JAVAC12
Hello blah = new Hello("Hello World") {
public void hello() {
System.err.println("overwritten");
}
};
///#endif
Inner blub = new Inner("Inner param") {
public void test() {
System.err.println("overwritten");
}
};
class Hi extends Inner {
public Hi() {
super("Hi World");
}
}
Vector v = new Vector(hi.var, new Inner("blah").var) {
public String newMethod() {
return super.toString();
}
};
Hi hu = new Hi();
}
}

@ -1,200 +0,0 @@
/* AnonymousJavac Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
import java.util.Vector;
public class AnonymousJavac {
class Inner {
int var = 3;
public void test() {
final long longVar = 5;
final double dblVar = 3;
class Hello {
int var = (int) longVar;
{
System.err.println("all constructors");
}
Hello() {
System.err.println("construct");
}
Hello(String info) {
System.err.println("construct: "+info);
}
// Hello(int i) {
// this("If you find a compiler that can compile this,"
// +" please comment this out and tell me if "
// +"decompilation works.\n"
// +"jikes 0.47, javac 1.2 are both broken!");
// }
public void hello() {
this.hashCode();
Inner.this.hashCode();
Inner.this.var = var;
AnonymousJavac.this.hashCode();
System.err.println("HelloWorld: "+dblVar);
}
};
final Hello hi = new Hello();
final Hello ho = new Hello("ho");
final Object o = new Object() {
int blah = 5;
Hello hii = hi;
Hello hoo = new Hello("hoo");
{
System.err.println("Anonymous Constructor speaking");
}
public String toString() {
this.hii.hello();
hi.hello();
return Integer.toHexString(AnonymousJavac.this.hashCode()
+blah);
}
{
System.err.println("Anonymous Constructor continues");
}
};
Object p = new Object() {
public String toString() {
return o.toString();
}
};
// Hello blah = new Hello("Hello World") {
// public void hello() {
// System.err.println("overwritten");
// }
// };
Inner blub1 = new Inner("Inner param") {
Hello hii = hi;
public void test() {
System.err.println("overwritten: "+hii+hi);
}
};
Inner blub2 = new AnonymousJavac().new Inner("Inner param") {
Hello hii = hi;
public void test() {
System.err.println("overwritten: "+hii);
AnonymousJavac.this.hashCode();
}
};
class Hi extends Inner {
public Hi() {
super("Hi World");
}
}
Vector v = new Vector(hi.var, var) {
Hello hii = hi;
public Object clone() {
return super.clone();
}
};
Hi hu = new Hi();
}
Inner (String str) {
}
}
public void test() {
class Hello {
int var = 4;
Hello() {
System.err.println("construct");
}
Hello(String info) {
System.err.println("construct: "+info);
}
public void hello() {
this.hashCode();
AnonymousJavac.this.hashCode();
System.err.println("HelloWorld");
}
};
final Hello hi = new Hello();
final Hello ho = new Hello("ho");
final Object o = new Object() {
int blah = 5;
Hello hii = hi;
public String toString() {
this.hii.hello();
hi.hello();
return Integer.toHexString(AnonymousJavac.this.hashCode()
+blah);
}
};
Object p = new Object() {
public String toString() {
return o.toString();
}
};
// Hello blah = new Hello("Hello World") {
// public void hello() {
// System.err.println("overwritten");
// }
// };
Inner blub1 = new Inner("Inner param") {
public void test() {
System.err.println("overwritten");
}
};
Inner blub2 = new AnonymousJavac().new Inner("Inner param") {
public void test() {
System.err.println("overwritten");
}
};
class Hi extends Inner {
public Hi() {
super("Hi World");
}
}
Vector v = new Vector(hi.var, new Inner("Hi").var) {
public Object clone() {
return super.clone();
}
};
Hi hu = new Hi();
}
}

@ -1,28 +0,0 @@
/* ArrayCloneTest Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class ArrayCloneTest {
public void test() {
int[] i = {4,3,2};
int[] j = (int[]) i.clone();
}
}

@ -1,92 +0,0 @@
/* ArrayTest Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
import java.io.*;
import java.lang.reflect.*;
public class ArrayTest {
Serializable s;
Serializable[] u;
Cloneable c;
public void test() {
int[] i = {4,3,2};
i = new int[] {1, 2, 3};
int[] j = new int[] {4,5,6};
int[][] k = {i,j};
u = k;
s = i;
c = i;
}
public void typetest() {
int[] arr = null;
s = arr;
c = arr;
arr[0] = 3;
arr = arr != null ? arr : new int[4];
}
public static void main(String[] param) {
int[] arr = new int[4];
Class cls = arr.getClass();
System.err.println("int[].getClass() is: "+cls);
System.err.println("int[].getClass().getSuperclass() is: "
+ cls.getSuperclass());
Class[] ifaces = cls.getInterfaces();
System.err.print("int[].getClass().getInterfaces() are: ");
for (int i = 0; i < ifaces.length; i++) {
if (i > 0)
System.err.print(", ");
System.err.print(ifaces[i]);
}
System.err.println();
Field[] fields = cls.getDeclaredFields();
System.err.print("int[].getClass().getDeclaredFields() are: ");
for (int i = 0; i < fields.length; i++) {
if (i > 0)
System.err.print(", ");
System.err.print(fields[i]);
}
System.err.println();
Method[] methods = cls.getDeclaredMethods();
System.err.print("int[].getClass().getDeclaredMethods() are: ");
for (int i = 0; i < methods.length; i++) {
if (i > 0)
System.err.print(", ");
System.err.print(methods[i]);
}
System.err.println();
Object o = arr;
System.err.println("arr instanceof Serializable: "+
(o instanceof Serializable));
System.err.println("arr instanceof Externalizable: "+
(o instanceof Externalizable));
System.err.println("arr instanceof Cloneable: "+
(o instanceof Cloneable));
// System.err.println("arr instanceof Comparable: "+
// (o instanceof Comparable));
}
}

@ -1,90 +0,0 @@
/* AssignOp Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class AssignOp {
static short static_short;
static int static_int;
static double static_double;
static String static_String;
static long static_long;
short obj_short;
int obj_int;
long obj_long;
double obj_double;
String obj_String;
short[] arr_short;
int [] arr_int;
long[] arr_long;
double[] arr_double;
String[] arr_String;
void assop() {
short local_short = 0;
int local_int = 0;
long local_long = 0;
double local_double = 1.0;
String local_String = null;
local_short -= 25 * local_int;
static_short += 100 - local_int;
obj_short /= 0.1;
arr_short[local_int] >>= 25;
local_long -= 15L;
static_long <<= local_int;
obj_long >>>= 3;
arr_long[4+local_int] *= obj_long - static_long;
local_int |= 25 | local_int;
static_int <<= 3;
obj_int *= 17 + obj_int;
arr_int[local_int] /= (obj_int+=7);
local_double /= 3.0;
static_double *= obj_int;
obj_double -= 25;
arr_double[local_int] /= (local_double+=7.0);
local_String += "Hallo";
static_String += "Hallo";
obj_String += "Hallo";
arr_String[0] += local_double + static_String + "Hallo" + obj_int;
}
void prepost() {
int local_int= -1;
long local_long= 4;
local_long = local_int++;
obj_long = ++obj_int;
arr_long[static_int] = static_long = (arr_long[--static_int] = (static_int--))+1;
}
void iinc() {
int local_int = 0;
local_int += 5;
obj_int = (local_int -= 5);
static_int = local_int++;
obj_int = --local_int;
}
}

@ -1,12 +0,0 @@
.class public Base
.super java/lang/Object
.field public static test I
.field public test J
.method <init>()V
aload_0
invokespecial java/lang/Object/<init>()V
return
.end method

@ -1,29 +0,0 @@
.class public Child
.super Base
.field private test I
.method <init>()V
.limit locals 1
.limit stack 2
aload_0
invokespecial Base/<init>()V
getstatic Base/test I
pop
aload_0
getfield Base/test J
pop2
aload_0
getfield Child/test I
pop
aload_0
getfield Child/test J
pop2
return
.end method
.method public static main([Ljava/lang/String;)V
.limit locals 1
.limit stack 0
return
.end method

@ -1,36 +0,0 @@
/* ClassOpTest Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class ClassOpTest {
static void test1() {
Class c1 = String.class;
Class c2 = Object.class;
if (ClassOpTest.class == null);
c1.getClass();
}
void test2() {
Class c2 = Object.class;
Class c3 = ClassOpTest.class;
Class c4 = int[].class;
Class c5 = Object[][].class;
Class c6 = int.class;
}
}

@ -1,71 +0,0 @@
/* ConstantTypes Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class ConstantTypes {
static boolean bool = true;
static byte b = (byte) 0x80;
static char c = '\u0080';
static short s = (short)'\u8234';
static int i = '\uffff';
static void intFunc(int i){}
static void shortFunc(short s){}
static void charFunc(char c){}
static void byteFunc(byte b){}
static {
/* All casts are necessaray */
intFunc(25);
shortFunc((short) 25);
charFunc((char) 25);
byteFunc((byte) 25);
intFunc('\u0019');
shortFunc((short) '\u0019');
charFunc('\u0019');
byteFunc((byte) '\u0019');
intFunc(b);
intFunc(c);
intFunc(s);
intFunc(i);
shortFunc(b);
shortFunc((short)c);
shortFunc(s);
shortFunc((short)i);
charFunc((char)b);
charFunc(c);
charFunc((char)s);
charFunc((char)i);
byteFunc(b);
byteFunc((byte)c);
byteFunc((byte)s);
byteFunc((byte)i);
b = 42;
c = 42;
s = 42;
i = 42;
i = c;
s = b;
i = s;
c = (char) s;
s = (short) c;
c = (char) b;
b = (byte) c;
}
}

@ -1,99 +0,0 @@
import jode.bytecode.*;
import java.util.*;
import com.sun.java.util.collections.Iterator;
public class CountOpcodes {
static int[] opcodeCount = new int[256];
static int[] predsCount = new int[1024];
static int[] succsCount = new int[1024];
static Vector instructions = new Vector(73400);
public static void handleBytecode(BytecodeInfo bc) {
for (Iterator i = bc.getInstructions().iterator(); i.hasNext();) {
Instruction instr = (Instruction) i.next();
instructions.addElement(instr);
opcodeCount[instr.getOpcode()]++;
Instruction[] p = instr.getPreds();
if (p == null)
predsCount[0]++;
else
predsCount[p.length]++;
Instruction[] s = instr.getSuccs();
if (s == null)
succsCount[0]++;
else
succsCount[s.length]++;
}
}
public static void handlePackage(String pack) {
Enumeration subs = ClassInfo.getClassesAndPackages(pack);
while (subs.hasMoreElements()) {
String comp = (String) subs.nextElement();
String full = pack + "." + comp;
if (ClassInfo.isPackage(full))
handlePackage(full);
else {
ClassInfo clazz = ClassInfo.forName(full);
clazz.loadInfo(ClassInfo.FULLINFO);
MethodInfo[] ms = clazz.getMethods();
for (int i=0; i < ms.length; i++) {
BytecodeInfo bc = ms[i].getBytecode();
if (bc != null)
handleBytecode(bc);
}
}
}
}
public static void main(String[] params) {
ClassInfo.setClassPath(params[0]);
Runtime runtime = Runtime.getRuntime();
long free = runtime.freeMemory();
long last;
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used before: "+(runtime.totalMemory()- free));
long time = System.currentTimeMillis();
handlePackage("com");
System.err.println("Time used: "+(System.currentTimeMillis() - time));
free = runtime.freeMemory();
do {
last = free;
runtime.gc();
runtime.runFinalization();
free = runtime.freeMemory();
} while (free < last);
System.err.println("used after: "+(runtime.totalMemory()- free));
System.err.println("instruction count: "+instructions.size());
for (int i=0; i< 256; i++) {
if (opcodeCount[i] > 0)
System.err.println("Opcode "+i+": \t ("+Opcodes.opcodeString[i]+")\t"+opcodeCount[i]);
}
int moreThanTwo = 0;
for (int i=0; i< predsCount.length; i++) {
if (predsCount[i] > 0) {
System.err.println("preds "+i+": \t"+predsCount[i]);
if (i>1)
moreThanTwo +=predsCount[i];
}
}
System.err.println("preds >2: \t"+moreThanTwo);
moreThanTwo = 0;
for (int i=0; i< succsCount.length; i++) {
if (succsCount[i] > 0) {
System.err.println("succs "+i+": \t"+succsCount[i]);
if (i>1)
moreThanTwo +=succsCount[i];
}
}
System.err.println("succs >2: \t"+moreThanTwo);
}
}

@ -1,124 +0,0 @@
; This class converts between boolean and ints without type casts.
; You can't decompile this directly, the decompiler probably gives type errors.
.class public EvilTypes
.super java/lang/Object
.field public static runner Ljava/lang/Runnable;
.method public static boolToInt(Z)I
.limit locals 1
.limit stack 1
iload_0
ireturn
.end method
.method public static intToBool(I)Z
.limit locals 1
.limit stack 1
iload_0
ireturn
.end method
.method public static overrideParam(I)[I
.limit locals 1
.limit stack 1
aconst_null
astore_0
aload_0
areturn
.end method
.method public static test()V
.limit locals 2
.limit stack 2
iconst_1
invokestatic EvilTypes/intToBool(I)Z
istore 0
iconst_2
istore 1
iload 0
iload 1
ixor
pop
return
.end method
.method private static useSerial(Ljava/io/Serializable;)V
.limit locals 1
.limit stack 0
return
.end method
; This is a test where a type error occurs, because there is no Type
; that implements Cloneable, Serializable and is assignable form int
; array and java/lang/Date (though both objects are Cloneable and
; Serializable). We can't find any correct type for local 2.
.method public static referenceCast(Ljava/util/Date;[I)Ljava/lang/Cloneable;
.limit locals 3
.limit stack 2
aload_0
ifnonnull second
aload_0
goto done
second:
aload_1
done:
dup
astore_2
invokestatic EvilTypes/useSerial(Ljava/io/Serializable;)V
aload_2
areturn
.end method
; This shows that the bytecode verifier doesn't catch every type error.
.method public static test(Ljava/lang/String;)Ljava/lang/Runnable;
.limit locals 1
.limit stack 1
aload_0
areturn
.end method
; The problem of this method is the type of local_0, the code is as
; follows:
; local_0 = null;
; for (;;) local_0 = local_0[0];
;
; Since local_0 is used as an array, it must be of array type. Since
; local_0[0] is assigned to local_0, local_0[0] must be of array type,
; so local_0 must be of type array of array of something, and so on...
.method public static infinitiveArray()V
.limit locals 1
.limit stack 2
aconst_null
astore_0
loop:
aload_0
iconst_0
aaload
astore_0
goto loop
.end method
; This tests shows how lazy the type checking even with verify is:
; The type error produced in the test method, is first seen on the
; invokeinterface opcode. If there would be no invokeinterface it
; would never have been noticed.
; NOTE: An obfuscator may use this fact and replace every ocurrence
; of an interface or Object type with any other interface type.
.method public static main([Ljava/lang/String;)V
.limit locals 1
.limit stack 2
aload_0
iconst_0
aaload
invokestatic EvilTypes/test(Ljava/lang/String;)Ljava/lang/Runnable;
putstatic EvilTypes/runner Ljava/lang/Runnable;
getstatic EvilTypes/runner Ljava/lang/Runnable;
invokeinterface java/lang/Runnable/run()V 1
return
.end method

@ -1,91 +0,0 @@
/* Expressions Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class Expressions {
double cd;
float cf;
long cl;
int ci;
char cc;
short cs;
byte cb;
boolean cz;
void postIncDecExpressions() {
cd++;
cf++;
cl++;
ci++;
cs++;
cb++;
cc++;
cd--;
cf--;
cl--;
ci--;
cs--;
cb--;
cc--;
float f = 0.0F;
double d = 0.0;
long l = 0L;
f++;
f--;
d++;
d--;
l++;
l--;
}
void unary() {
short s = 25;
s = (short) ~s;
boolean b = !true;
s = b? s: cs;
char c= 25;
c = b ? c: cc;
}
void shift() {
int i = 0;
long l =0;
l >>= i;
l >>= i;
i >>= i;
l = l << l;
l = l << i;
l = i << l;
l = i << i;
i = (int) (l << l);
i = (int) (l << i);
i = i << l;
i = i << i;
cl >>= ci;
ci <<= ci;
cl = cl << cl;
cl = cl << ci;
cl = ci << cl;
cl = ci << ci;
ci = (int) (cl << cl);
ci = (int) (cl << ci);
ci = ci << cl;
ci = ci << ci;
}
}

@ -1,218 +0,0 @@
/* Flow Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public abstract class Flow {
int g;
int[] ain;
void skip() {
for (int i=0; i<3; i++) {
if (g > 5) {
for (int j=0; j<5; j++) {
g++;
}
}
i--;
}
}
/* This tests the while in a switch problem.
*/
public void switchWhileTest() {
int dir = g;
int x = 0;
int y = 0;
boolean done = false;
g = 5;
switch (dir) {
case 1:
while (!done) {
done = true;
if (g > 7)
g = g - 4;
x = g;
y = g;
if (x > 7)
x = x - 4;
for (int i=0; i<4; i++) {
for (int j=0; j<5; j++) {
if (ain[j] == x + i && ain[j] == y)
done = false;
}
}
}
for (int i=0; i<5; i++) {
ain[g] = x + i;
ain[g] = y;
g += 1;
}
break;
case 2:
while (!done) {
done = true;
x = g;
y = g;
if (y > 7)
y = y - 4;
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (ain[j] == x && ain[j] == y + i)
done = false;
}
}
}
for (int i = 0; i<4; i++) {
ain[g] = x;
ain[g] = y + i;
g += 1;
}
break;
case 3: // Same code as case 2 slightly optimized
big:
for (;;) {
x = g;
y = g;
if (y > 7)
y = y - 4;
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
if (ain[j] == x && ain[j] == y + i)
continue big;
}
}
break;
}
for (int i = 0; i<4; i++) {
ain[g] = x;
ain[g] = y + i;
g += 1;
}
break;
}
}
/**
* This was an example where our flow analysis didn't find an
* elegant solution. The reason is, that we try to make
* while(true)-loops as small as possible (you can't see the real
* end of the loop, if it is breaked there like here).
*
* Look at the assembler code and you know why my Decompiler had
* problems with this. But the decompiler did produce compilable
* code which produces the same assembler code.
*
* The solution was, to make switches as big as possible, the whole
* analyze methods were overworked.
*/
void WhileTrueSwitch() {
int i = 1;
while (true) {
switch (i) {
case 0:
return;
case 1:
i = 5;
continue;
case 2:
i = 6;
continue;
case 3:
throw new RuntimeException();
default:
i = 7;
return;
}
}
}
abstract int test();
/**
* This tests shorts and empty ifs. Especially the no op ifs can
* be optimized to very unusual code.
*/
public void shortIf() {
while(g != 7) {
if (g == 5)
return;
else if (g != 4)
break;
else if (g == 2)
shortIf();
else
return;
if (g!= 7)
shortIf();
else {
shortIf();
return;
}
if (g != 1)
break;
else if (g == 3)
shortIf();
else
break;
// javac optimizes this instruction to
// test();
// jikes reproduces this statement as one would expect
if (g + 5 == test()) {
}
// javac -O optimizes this to the following weired statements
// PUSH g;
// PUSH test();
// POP2;
// This cannot be decompiled correctly, since the == is lost.
if (g == test())
continue;
}
while(g == 3) {
// javac:
// PUSH test() == 4 || test() == 3 && test() == 2;
// POP;
if (test() == 4 || test() == 3 && test() == 2);
// javac -O:
// if (test() != 4 && test() == 3) {
// PUSH test()+test() - test();
// PUSH g-4;
// POP2;
// }
if (test() == 4 || test() == 3 && test() == 2)
continue;
}
while (g==2) {
// javac:
// test();
// test();
// test();
if ((long) (test() + test() - test()) == (long)(g-4));
// javac -O:
// PUSH (long)(test() + test() - test()) <=> (long)(g-4)
// POP;
if ((long) (test() + test() - test()) == (long)(g-4))
continue;
}
System.err.println("Hallo");
}
}

@ -1,35 +0,0 @@
/* For Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class For {
boolean nested() {
outer:
for (int i=0; i< 100; i++) {
for (int j=0; j< 100; j++) {
if (i < j)
continue outer;
}
return false;
}
return true;
}
}

@ -1,50 +0,0 @@
/* HintTypeTest Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/**
* The primitive types can give some headaches. You almost never can say
* if a local variable is of type int, char, short etc. <p>
*
* Most times this doesn't matter this much, but with int and character's
* this can get ugly. <p>
*
* The solution is to give every variable a hint, which type it probably is.
* The hint reset, when the type is not possible. For integer types we try
* to set it to the smallest explicitly assigned type. <p>
*
* Some operators will propagate this hint.<p>
*/
public class HintTypeTest {
public void charLocal() {
String s= "Hallo";
for (byte i=0; i< s.length(); i++) {
char c = s.charAt(i);
if (c == 'H')
// The widening to int doesn't occur in byte code, but
// is necessary. This is really difficult.
System.err.println("H is "+(int)c);
else
System.err.println(""+c+" is "+(int)c);
}
}
}

@ -1,33 +0,0 @@
/* IfCombine Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class IfCombine {
boolean a,b,c;
int i,j,k;
public void foo() {
if ( a && (b || c) && (i<k)) {
if (a != b)
i = 1;
else
i = 2;
}
}
}

@ -1,34 +0,0 @@
/* InlineTest Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/**
* Check if inlines are allowed over package borders. You should put it
* in a different package to check if inlining works over package borders.
*
* @author Jochen Hoenicke
* @see jode.test.OptimizeTest
*/
public class InlineTest {
public static final int
difficultSideInline(jode.test.OptimizeTest ot, int a) {
return ot.g++ + a;
}
}

@ -1,21 +0,0 @@
public class InlinedAnon {
private final Object getAnon(final int param) {
return new Object() {
public String toString() {
return ""+param;
}
};
}
void test1() {
Object o1 = getAnon(5);
Object o2 = getAnon(3);
}
void test2() {
Object o3 = getAnon(1);
Object o4 = getAnon(2);
}
}

@ -1,99 +0,0 @@
/* InnerClass Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class InnerClass
{
private int x;
class Parent
{
int a = 1;
protected int x;
void ambiguous() {
System.err.println("Parent");
}
}
class Inner
{
int a = 4;
private int b = x;
class InnerInner extends Parent
{
public int getB() {
return Inner.this.getB();
}
public int getStaticB(InnerInner innerinner) {
createInner(InnerClass.this);
return innerinner.getB();
}
public InnerInner(int c) {
this.x = c;
InnerClass.this.x = b;
this.a = b;
Inner.this.a = c;
this.ambiguous();
Inner.this.ambiguous();
InnerClass.this.ambiguous();
}
}
void ambiguous() {
System.err.println("Inner");
}
private int getB() {
return b;
}
public InnerInner createInnerInner(int a) {
return new InnerInner(a);
}
}
class Extended
extends Inner.InnerInner
{
Extended(Inner inner) {
inner.super(3);
this.ambiguous();
InnerClass.this.ambiguous();
}
}
void ambiguous() {
System.err.println("InnerClass");
}
private static Inner createInner(InnerClass outer) {
return outer.new Inner();
}
InnerClass() {
new Inner().createInnerInner(10).getB();
createInner(this).new InnerInner(42);
}
}

@ -1,69 +0,0 @@
/* InnerCompat Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class InnerCompat {
int x;
private class privateNeedThis {
void a() { x = 5; }
}
protected class protectedNeedThis {
void a() { x = 5; }
}
class packageNeedThis {
void a() { x = 5; }
}
public class publicNeedThis {
void a() { x = 5; }
}
private class privateNeedNotThis {
int x;
void a() { x = 5; }
}
protected class protectedNeedNotThis {
int x;
void a() { x = 5; }
}
class packageNeedNotThis {
int x;
void a() { x = 5; }
}
public class publicNeedNotThis {
int x;
void a() { x = 5; }
}
private static class privateStatic {
int x;
void a() { x = 5; }
}
protected static class protectedStatic {
int x;
void a() { x = 5; }
}
static class packageStatic {
int x;
void a() { x = 5; }
}
public static class publicStatic {
int x;
void a() { x = 5; }
}
}

@ -1,33 +0,0 @@
/**
* This class shows a bug in javac 1.2-pre2 compiler.
* Decompile the generated class to see whats happening.
*/
public class JavacBug {
class Inner {
public String toString() {
return "Inner";
}
}
public Inner test() {
final int a = 1;
final int b = 2;
return new Inner() {
/* jdk1.2 javac misses these initializers */
int c = a;
int d = 3;
public String toString() {
return "b="+b+"; c="+c+"; d="+d;
}
};
}
public static void main(String[] argv) {
Inner inner = new JavacBug().test();
System.err.println(inner.toString());
}
}

@ -1,63 +0,0 @@
.class public JsrTest
.super java/lang/Object
.method public static main([Ljava/lang/String;)V
.limit locals 3
.limit stack 5
jsr big_sub
jsr evil_jsrret
astore_1
returninstr:
return
evil_jsrret:
astore_2
jsr retinstr
retinstr:
ret 2
big_sub:
astore_2
aload_0
astore_1
aload_0
ifnull skip
jsr subroutine
skip:
aload_0
ifnull end
jsr sub2
end:
ret 2
subroutine:
astore_1
aload_0
ifnull gotoend1
aload_0
ifnonnull bothsubs
ret 1
gotoend1:
jsr innermostSub
goto returninstr
sub2:
astore_1
aconst_null
ifnonnull bothsubs
ret 1
bothsubs:
aload_0
ifnull end
jsr innermostSub
goto end
innermostSub:
astore_1
ret 1
.end method

@ -1,183 +0,0 @@
/* LocalTypes Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
class A {
}
interface I1 {
}
interface I2 {
}
interface I12 extends I1, I2 {
}
class B extends A implements I1 {
}
class C extends B implements I2, I12 {
}
class D extends A implements I12 {
}
class E extends A implements I2 {
}
public class LocalTypes {
A a;
B b;
C c;
D d;
E e;
I1 i1;
I2 i2;
I12 i12;
boolean g_bo;
byte g_by;
short g_sh;
int g_in;
int z;
int[]ain;
public void arithTest() {
int a=1,b=2;
boolean xb = true,yb = false;
int xi = 1,yi = 0;
int c=0;
arithTest();
if ((xb & yb) || (xi & yi) != 0) {
c = 5;
arithTest();
xb &= yb;
xi &= yi;
arithTest();
xb = xb | yb;
xi = xi | yi;
arithTest();
xb ^= yb;
xi ^= yi;
arithTest();
xb = xb && yb;
xi = (xi != 0) && (yi != 0) ? 1 : 0;
arithTest();
b <<= a;
b <<= c;
}
xi++;
a&=b;
}
public void intTypeTest() {
boolean b = false;
boolean abo[] = null;
byte aby[] = null;
byte by;
int in;
short sh;
b = g_bo;
in = g_sh;
sh = (short)g_in;
by = (byte)sh;
sh = by;
in = by;
abo[0] = g_bo;
abo[1] = false;
abo[2] = true;
aby[0] = g_by;
aby[1] = 0;
aby[2] = 1;
}
native void arrFunc(B[] b);
/**
* This is an example where it is really hard to know, which type
* each local has.
*/
void DifficultType () {
B myB = c;
C myC = c;
I2 myI2 = c;
I12 myI12 = c;
boolean bool = true;
B[] aB = new C[3];
arrFunc(new C[3]);
while (bool) {
if (bool) {
i1 = myB;
i2 = myC;
i1 = aB[0];
} else if (bool) {
i1 = myI12;
i2 = myI2;
} else {
i1 = myC;
i2 = myI12;
}
myB = b;
if (bool)
myI2 = i12;
else {
myI12 = d;
myI2 = e;
}
}
}
/**
* This is an example where it is really hard to know, which type
* each local has.
*/
void DifficultArrayType () {
boolean bool = true;
B[] aB = new C[3];
arrFunc(new C[3]);
C[][][][][] x = new C[4][3][4][][];
int[][][][][] y = new int[1][2][][][];
while (bool) {
if (bool) {
i1 = aB[0];
aB[0] = b;
}
}
}
public void castTests() {
System.err.println(null instanceof int[]);
System.err.println(((Object)new int[4]) instanceof byte[]);
System.err.println(((Object)new byte[4]) instanceof int[]);
System.err.println(((Object)new int[4]) instanceof LocalTypes);
System.err.println(((Object)new int[4]) instanceof int[][]);
System.err.println(new Object[4] instanceof int[][]);
System.err.println(new int[5][4] instanceof java.io.Serializable[]);
System.err.println(((Object)this) instanceof RuntimeException);
System.err.println(((RuntimeException)(Object)this).getMessage());
((java.io.PrintStream)null).println("Hallo");
((LocalTypes) null).a = ((LocalTypes) null).b;
}
}

@ -1,6 +0,0 @@
JAVA = @JAVA@
JAVAC = @JAVAC@
JFLAGS =
TESTS_ENVIRONMENT=JAVA=$(JAVA) JAVAC=$(JAVAC) JFLAGS=$(JFLAGS) srcdir=$(srcdir) top_srcdir=$(top_srcdir) top_builddir=$(top_builddir)
TESTS = simpletests.sh

@ -1,17 +0,0 @@
public class NestedAnon {
public NestedAnon(int maxdepth) {
class NestMyself {
int depth;
NestMyself son;
public NestMyself(int d) {
depth = d;
if (d > 0)
son = new NestMyself(d-1);
}
}
new NestMyself(maxdepth);
}
}

@ -1,166 +0,0 @@
; This class contains a hand optimized (and hard to decompile)
; string obfuscating method. Maybe I will use it in the Obfuscator
; some day, but probably the decompiler will handle those string, too.
.class public ObfuscateStrings
.super java/lang/Object
.method private static obf(Ljava/lang/String;)Ljava/lang/String;
.limit locals 1
.limit stack 7
aload_0
invokevirtual java/lang/String/toCharArray()[C
dup
iconst_0
ldc 0x12345678
goto firstloop
loopstart:
; next pseudo random
; char array
dup_x1
swap
iload_0
swap
ldc 0x7fffffff
iand
firstloop:
;stack content:
; char array
; char array copy
; current index
; current pseudo random
ldc 1103515245
imul
sipush 12345
iadd
dup_x2
sipush 0xff
iand
dup_x2
pop
;stack content:
; char array
; next pseudo random
; xor mask
; char array copy
; current index
dup2_x1
;stack content:
; char array
; next pseudo random
; char array copy
; current index
; xor mask
; char array copy
; current index
caload
ixor
;stack content:
; char array
; next pseudo random
; char array copy
; current index
; new char
swap
dup_x1
istore_0
iinc 0 1
castore
;stack content:
; char array
; next pseudo random
;locals: 1 = current index
swap
dup
arraylength
iload_0
if_icmpne loopstart
new java/lang/String
dup_x2
swap
invokespecial java/lang/String/<init>([C)V
pop
areturn
.end method
.method private static obf2(Ljava/lang/String;)Ljava/lang/String;
.limit locals 1
.limit stack 8
aload_0
invokevirtual java/lang/String/toCharArray()[C
ldc 0x12345678
istore_0
iconst_0
loop:
; char array
; next index
;stack content:
; char array
; current index
dup2
dup2
caload
; char array
; current index
; char array
; current index
; original char
iload_0
ldc 0x7fffffff
iand
dup
ldc 1103515245
imul
sipush 12345
iadd
istore_0
sipush 0xff
iand
ixor
; char array
; current index
; char array
; current index
; new char
castore
iconst_1
iadd
; char array
; next index
dup2
swap
arraylength
if_icmplt loop
; char array
; next index
pop
new java/lang/String
dup_x1
swap
invokespecial java/lang/String/<init>([C)V
areturn
.end method

@ -1,79 +0,0 @@
/* OptimizeTest Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class OptimizeTest {
public final int getInlined(String str, int i) {
return str.charAt(i);
}
public final int getInlined(String str, int i, OptimizeTest t) {
return str.charAt(i) + t.getInlined(str, i) + i;
}
public final int complexInline(String str, int i) {
System.err.println("");
return str.charAt(i)+str.charAt(-i);
}
public int notInlined(String str, int i, OptimizeTest t) {
return str.charAt(i) + t.getInlined(str, i);
}
public final void longInline(String str, int i) {
str.replace('a','b');
System.err.println(str.concat(String.valueOf(str.charAt(i))));
}
public int g;
/**
* This is a really brutal test. It shows that side effects can
* make the handling of inlined methods really, really difficult.
*/
public final int sideInline(int a) {
return g++ + a;
}
public void main(String[] param) {
OptimizeTest ot = new OptimizeTest();
System.err.println(ot.getInlined("abcde".replace('a','b'), param.length));
System.err.println(ot.getInlined("Hallo", ot.notInlined(param[1], 10 - ot.getInlined(param[0], 0, new OptimizeTest()), ot)));
System.err.println(ot.complexInline("ollah", param.length));
System.err.println("result: "+(g++ + sideInline(g) + g++) + "g: "+g);
longInline("Hallo", 3);
System.err.println("result:"+
(g++ + InlineTest
.difficultSideInline(this, g)
+ g++) + "g: "+g);
// This was a check which methods are inlined. The result:
// Only methods in the same package or in sub packages.
// System.err.println("result:"+
// (g++ + inline.InlineTest
// .difficultSideInline(this, g)
// + g++) + "g: "+g);
// System.err.println("result:"+
// (g++ + jode.InlineTest
// .difficultSideInline(this, g)
// + g++) + "g: "+g);
}
}

@ -1,58 +0,0 @@
/**
* This class should be optimized through the obfuscator:
*
* <pre>
* java jode.Obfuscator --dest tmp.zip --preserve 'jode.test.OptimizerTest.test.(*)*' jode
* </pre>
*/
public class OptimizerTest {
String blah, blub;
Object o;
private static String manipulateString(String input) {
char[] chars = input.toCharArray();
char[] dests = new char[chars.length];
dests[0] = chars[0];
for (int i=1; i< chars.length; i++) {
if (chars[i] > chars[i-1]) {
dests[i] = (char) (chars[i] - chars[i-1]);
} else if (chars[i] == chars[i-1]) {
dests[i] = 0;
} else if (chars[i] < chars[i-1]) {
dests[i] = (char) (Character.MAX_VALUE
- (chars[i-1] - chars[i] - 1));
} else
dests[i] = 'X';
}
return new String(dests);
}
public static String doubleCompare(double d1, double d2) {
return d1 + ((d1 > d2) ? " > "
: (d1 < d2) ? " < "
: (d1 == d2) ? " == " : " ?? ") + d2;
}
public void test() {
System.err.println(manipulateString("ABCDEFGGFEDCBA"));
blah = manipulateString("hello world");
o = new Object();
blub = "Hallo"+manipulateString("ABCDEFGGFDECBA");
System.err.println(blub);
System.err.println(doubleCompare(0.0, 0.0));
System.err.println(doubleCompare(0.0, 1.0));
System.err.println(doubleCompare(0.0, -1.0));
System.err.println(doubleCompare(0.0, Double.NaN));
System.err.println(doubleCompare(Double.NaN, 0.0));
System.err.println(doubleCompare(Double.NaN, Double.NaN));
System.err.println(doubleCompare(Double.NEGATIVE_INFINITY,
Double.POSITIVE_INFINITY));
System.err.println(doubleCompare(Math.exp(1), 2.718281828459045));
System.err.println((int)Math.round(Math.exp(Math.log(5)*5))/ 625);
}
}

@ -1,70 +0,0 @@
.class public RemovePopExample
.super java/lang/Object
.field private sng I
.field private dlb J
.field private obj Ljava/lang/Object;
.method <init>()V
.limit locals 1
.limit stack 1
aload_0
invokespecial java/lang/Object/<init>()V
return
.end method
.method singlePop()V
.limit locals 3
.limit stack 20
iconst_0
istore 0
iconst_0
pop
dconst_0
pop2
iload_0
pop
aconst_null
iconst_0
iaload
pop
iconst_0
dup
pop
dup
istore_0
pop
lconst_1
iconst_0
dup_x2
lshl
lstore_1
pop
iload_0
iconst_4
dup_x1
pop
pop2
iconst_4
lload_1
dup2
pop2
dup2_x1
lstore_1
istore_0
pop2
return
.end method

@ -1,112 +0,0 @@
/* Conflicts Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/**
* This class tests name conflicts and their resolvation. Note that every
* name in this file should be the shortest possible name.
*/
public class ResolveConflicts
{
public class Conflicts
{
int Conflicts;
class Blah
{
Conflicts Inner;
void Conflicts() {
Inner = ResolveConflicts.Conflicts.this;
}
}
class Inner
{
int Conflicts;
Conflicts Inner;
class Blah
extends Conflicts.Blah
{
int Blah;
void Inner() {
this.Inner.Inner();
ResolveConflicts.Conflicts.Inner.this.Inner.Inner();
this.Conflicts();
ResolveConflicts.Conflicts.Inner.this.Conflicts();
}
Blah() {
/* empty */
}
Blah(Conflicts Conflicts) {
Conflicts.super();
}
}
void Conflicts() {
int Conflicts = 4;
Conflicts();
new Object() {
void Inner() {
ResolveConflicts.Conflicts.this.Inner();
}
};
this.Conflicts = Conflicts;
Inner();
ResolveConflicts.Conflicts.this.Conflicts = this.Conflicts;
}
Conflicts Conflicts(Inner Conflicts) {
return ResolveConflicts.Conflicts.this;
}
}
class Second
extends Conflicts.Inner.Blah
{
Inner Blah = new Inner();
class Inner extends Conflicts.Inner
{
}
Conflicts.Inner create() {
return ResolveConflicts.Conflicts.this.new Inner();
}
Second(Conflicts.Inner Blah) {
Blah.super();
}
}
public void Inner() {
/* empty */
}
public Conflicts() {
int Conflicts = this.Conflicts;
Inner Inner = new Inner();
Inner.Conflicts = 5;
new Inner().Conflicts(Inner).Inner();
}
}
}

@ -1,41 +0,0 @@
; This class contains evil stack operations, that make it very hard to
; produce correct code.
.class public StackOps
.super java/lang/Object
.method public static concatSwaped(ZLjava/lang/String;Ljava/lang/String;)Ljava/lang/String;
.limit locals 3
.limit stack 3
aload_1
aload_2
iload 0
ifeq dontswap
swap
dontswap:
invokevirtual java/lang/String/concat(Ljava/lang/String;)Ljava/lang/String;
areturn
.end method
.method public static dupTest(Ljava/lang/String;)Ljava/lang/String;
.limit locals 1
.limit stack 2
; first a simple test that we can resolve
aload_0
dup
invokevirtual java/lang/String/concat(Ljava/lang/String;)Ljava/lang/String;
; now concat again.
dup
invokevirtual java/lang/String/concat(Ljava/lang/String;)Ljava/lang/String;
; Now a more evil test.
aload_0
swap
ifnull pushagain
dup
goto concat
pushagain:
aload_0
concat:
invokevirtual java/lang/String/concat(Ljava/lang/String;)Ljava/lang/String;
areturn
.end method

@ -1,38 +0,0 @@
/* TriadicExpr Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
public class TriadicExpr {
int a,b,c,d,e,f,g,h,i,j;
boolean bool;
void test() {
if( (a< b ? bool : (a<b)))
a=b;
else
b=a;
if ((a<b?b<a:i<j) ? (c<d ? e<f : g < h) : (j<i ? h<g:f<e))
a=(b<a ? g : h);
else
b=a;
}
}

@ -1,159 +0,0 @@
/* TryCatch Copyright (C) 1998-1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
/**
* This tests everything that has to do with a ExceptionHandler, that
* is try, catch, finally and synchronized.
*/
class TryCatch {
int simple() {
TryCatch i = null;
try {
foo();
} catch (RuntimeException ex) {
ex.printStackTrace();
} catch (Exception ex) {
return 0;
} finally {
simple();
}
synchronized(this) {
System.gc();
if (i != null)
return -1;
}
synchronized(i) {
foo();
}
return 1;
}
int localsInCatch() {
int a = 0;
try {
a = 1;
foo();
a = 2;
simple();
a = (a=4) / (a=0);
a = 3;
localsInCatch();
a = 4;
return 5;
} catch (Exception ex) {
return a;
}
}
int finallyBreaks() {
try {
simple();
throw new Exception();
} catch (Exception ex) {
return 3;
} finally {
simple();
return 3;
}
}
int whileInTry() {
int a=1;
try {
while (true) {
a= 4;
whileInTry();
}
} finally {
synchronized(this) {
while (true) {
foo();
if (a == 5)
break;
finallyBreaks();
}
}
return a;
}
}
void foo() {
TryCatch local = null;
while (true) {
foo();
synchronized (this) {
System.gc();
try {
System.err.println();
} catch (RuntimeException ex) {
ex.printStackTrace();
for (int i=0; i<4; i++)
foo();
break;
} finally {
System.out.println();
for (int i=0; i<4; i++)
foo();
System.out.println();
}
}
}
synchronized (local) {
local.foo();
}
if (simple() == 0) {
synchronized (this) {
try {
System.err.println();
} finally {
Thread.dumpStack();
return;
}
}
}
System.out.println();
}
void oneEntryFinally() {
try {
throw new RuntimeException("ex");
} finally {
System.err.println("hallo");
}
}
void finallyMayBreak() {
while(simple() > 3) {
try {
System.err.println();
} finally {
if (simple() < 2)
break;
else if (simple() < 3)
foo();
else
return;
}
System.out.println();
}
System.err.println();
}
}

@ -1,32 +0,0 @@
/* Unreach Copyright (C) 1999 Dave Mugridge.
*
* $Id$
*/
/* A test class submitted by dave@onekiwi.demon.co.uk */
class Unreach
{
static int j = 0;
final double[] d = {0.5, 0.4, 0.3}; // won't decompile
public static final void m(int i) throws Exception {
switch (i) {
case 1:
j += 2;
for (;;) {
j += 3;
switch (j) {
case 2:
break;
default:
j += 4;
return;
}
}
// An unreachable break is inserted here
default:
j += 5; // decompiles as j = j + 1; -- not quite optimal
}
}
}

@ -1,7 +0,0 @@
classpath = "."
load = new WildCard { value = "RemovePopExample" }
preserve = new WildCard { value = "*" }
analyzer = new SimpleAnalyzer
post = new RemovePopAnalyzer

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save