git-svn-id: https://svn.code.sf.net/p/jode/code/tags/jode_1_0_91@1156 379699f6-c40d-0410-875b-85095c16579ejode_1_0_91
parent
ff298fb733
commit
65ce4f3b53
@ -1 +0,0 @@ |
|||||||
*.class |
|
@ -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 <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…
Reference in new issue