instructions now collectionified

Use listIterator to manipulate bytecode
Some bug fixes
More use of TypeSignature, and prevent using of jode.type.Type


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1097 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent dcd5686bc2
commit c3ead8b084
  1. 154
      jode/jode/obfuscator/ClassBundle.java.in
  2. 34
      jode/jode/obfuscator/ClassIdentifier.java.in
  3. 226
      jode/jode/obfuscator/ConstantAnalyzer.java.in
  4. 24
      jode/jode/obfuscator/FieldIdentifier.java.in
  5. 97
      jode/jode/obfuscator/LocalOptimizer.java.in
  6. 0
      jode/jode/obfuscator/LocalizeFieldTransformer.java.in
  7. 1
      jode/jode/obfuscator/Makefile.am
  8. 24
      jode/jode/obfuscator/MethodIdentifier.java.in
  9. 77
      jode/jode/obfuscator/PackageIdentifier.java.in
  10. 262
      jode/jode/obfuscator/RemovePopAnalyzer.java
  11. 307
      jode/jode/obfuscator/RemovePopAnalyzer.java.in
  12. 4
      jode/jode/obfuscator/ScriptParser.java.in
  13. 40
      jode/jode/obfuscator/SimpleAnalyzer.java.in
  14. 1
      jode/jode/obfuscator/UniqueRenamer.java.in

@ -99,6 +99,21 @@ public class ClassBundle implements OptionHandler {
return; 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")) { if (option.equals("strip")) {
next_token: next_token:
for (Iterator iter = values.iterator(); iter.hasNext(); ) { for (Iterator iter = values.iterator(); iter.hasNext(); ) {
@ -116,33 +131,72 @@ public class ClassBundle implements OptionHandler {
} }
if (option.equals("load")) { if (option.equals("load")) {
if (values.size() == 1) if (values.size() == 1) {
loading = (IdentifierMatcher) values.iterator().next(); Object value = values.iterator().next();
else 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 loading = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, (IdentifierMatcher[]) (MultiIdentifierMatcher.OR, matchers);
values.toArray(new IdentifierMatcher[values.size()])); }
return; return;
} }
if (option.equals("preserve")) { if (option.equals("preserve")) {
if (values.size() == 1) if (values.size() == 1) {
preserving = (IdentifierMatcher) values.iterator().next(); Object value = values.iterator().next();
else 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 preserving = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, (IdentifierMatcher[]) (MultiIdentifierMatcher.OR, matchers);
values.toArray(new IdentifierMatcher[values.size()])); }
return; return;
} }
if (option.equals("reach")) { if (option.equals("reach")) {
// NOT IMPLEMENTED YET // NOT IMPLEMENTED YET
if (values.size() == 1) if (values.size() == 1) {
reaching = (IdentifierMatcher) values.iterator().next(); Object value = values.iterator().next();
else 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 reaching = new MultiIdentifierMatcher
(MultiIdentifierMatcher.OR, (IdentifierMatcher[]) (MultiIdentifierMatcher.OR, matchers);
values.toArray(new IdentifierMatcher[values.size()])); }
} }
if (option.equals("pre")) { if (option.equals("pre")) {
@ -228,8 +282,22 @@ public class ClassBundle implements OptionHandler {
return ident.getIdentifier(ref.getName(), ref.getType()); return ident.getIdentifier(ref.getName(), ref.getType());
} }
public void reachableIdentifier(String fqn, boolean isVirtual) { public void reachableClass(String clazzName) {
basePackage.reachableIdentifier(fqn, isVirtual); 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) { public void analyzeIdentifier(Identifier ident) {
@ -340,7 +408,7 @@ public class ClassBundle implements OptionHandler {
} }
public Object next() { public Object next() {
return (last++ == 1 ? base : base + last); return (last++ == 0 ? base : base + last);
} }
public void remove() { public void remove() {
@ -349,24 +417,72 @@ public class ClassBundle implements OptionHandler {
}; };
} }
}; };
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"); GlobalOptions.err.println("Loading and preserving classes");
long time = System.currentTimeMillis();
basePackage.loadMatchingClasses(loading); basePackage.loadMatchingClasses(loading);
basePackage.applyPreserveRule(preserving); basePackage.applyPreserveRule(preserving);
System.err.println("Time used: "+(System.currentTimeMillis() - time));
GlobalOptions.err.println("Computing reachable settings"); GlobalOptions.err.println("Computing reachable settings");
time = System.currentTimeMillis();
analyze(); 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"); GlobalOptions.err.println("Renaming methods");
time = System.currentTimeMillis();
if (tableFile != null) if (tableFile != null)
readTable(); readTable();
buildTable(renamer); buildTable(renamer);
if (toTableFile != null) if (toTableFile != null)
writeTable(); writeTable();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
GlobalOptions.err.println("Transforming the classes"); GlobalOptions.err.println("Transforming the classes");
time = System.currentTimeMillis();
doTransformations(); 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"); GlobalOptions.err.println("Writing new classes");
time = System.currentTimeMillis();
storeClasses(); storeClasses();
System.err.println("Time used: "+(System.currentTimeMillis() - time));
} }
} }

@ -60,10 +60,8 @@ public class ClassIdentifier extends Identifier {
public void addSubClass(ClassIdentifier ci) { public void addSubClass(ClassIdentifier ci) {
knownSubClasses.add(ci); knownSubClasses.add(ci);
for(Iterator i = virtualReachables.iterator(); i.hasNext(); ) { for(Iterator i = virtualReachables.iterator(); i.hasNext(); )
String[] method = (String[]) i.next(); ci.reachableReference((Reference) i.next(), true);
ci.reachableIdentifier(method[0], method[1], true);
}
} }
private FieldIdentifier findField(String name, String typeSig) { private FieldIdentifier findField(String name, String typeSig) {
@ -86,13 +84,12 @@ public class ClassIdentifier extends Identifier {
return null; return null;
} }
public void reachableIdentifier(String name, String typeSig, public void reachableReference(Reference ref, boolean isVirtual) {
boolean isVirtual) {
boolean found = false; boolean found = false;
for (Iterator i = getChilds(); i.hasNext(); ) { for (Iterator i = getChilds(); i.hasNext(); ) {
Identifier ident = (Identifier) i.next(); Identifier ident = (Identifier) i.next();
if (name.equals(ident.getName()) if (ref.getName().equals(ident.getName())
&& typeSig.equals(ident.getType())) { && ref.getType().equals(ident.getType())) {
ident.setReachable(); ident.setReachable();
found = true; found = true;
} }
@ -108,14 +105,21 @@ public class ClassIdentifier extends Identifier {
ClassIdentifier superIdent = Main.getClassBundle() ClassIdentifier superIdent = Main.getClassBundle()
.getClassIdentifier(info.getSuperclass().getName()); .getClassIdentifier(info.getSuperclass().getName());
if (superIdent != null) if (superIdent != null)
superIdent.reachableIdentifier(name, typeSig, false); superIdent.reachableReference(ref, false);
} }
if (isVirtual) { 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(); ) for (Iterator i = knownSubClasses.iterator(); i.hasNext(); )
((ClassIdentifier)i.next()) ((ClassIdentifier)i.next())
.reachableIdentifier(name, typeSig, false); .reachableReference(ref, false);
virtualReachables.add(new String[] { name, typeSig }); virtualReachables.add(ref);
} }
} }
@ -308,14 +312,18 @@ public class ClassIdentifier extends Identifier {
superident.addSubClass(this); superident.addSubClass(this);
} else { } else {
// all virtual methods in superclass are reachable now! // all virtual methods in superclass are reachable now!
String clazzType = ("L"+superclass.getName().replace('.', '/')
+";").intern();
MethodInfo[] topmethods = superclass.getMethods(); MethodInfo[] topmethods = superclass.getMethods();
for (int i=0; i< topmethods.length; i++) { for (int i=0; i< topmethods.length; i++) {
int modif = topmethods[i].getModifiers(); int modif = topmethods[i].getModifiers();
if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL) if (((Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL)
& modif) == 0 & modif) == 0
&& !topmethods[i].getName().equals("<init>")) { && !topmethods[i].getName().equals("<init>")) {
reachableIdentifier reachableReference
(topmethods[i].getName(), topmethods[i].getType(), (Reference.getReference(clazzType,
topmethods[i].getName(),
topmethods[i].getType()),
true); true);
} }
} }

@ -38,6 +38,7 @@ import @COLLECTIONS@.Set;
import @COLLECTIONS@.HashMap; import @COLLECTIONS@.HashMap;
import @COLLECTIONS@.Map; import @COLLECTIONS@.Map;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/** /**
* Analyze the code, assuming every field that is not yet written to * Analyze the code, assuming every field that is not yet written to
@ -464,13 +465,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
public void handleReference(Reference ref, boolean isVirtual) { public void handleReference(Reference ref, boolean isVirtual) {
String clName = ref.getClazz(); Main.getClassBundle().reachableReference(ref, isVirtual);
/* Don't have to reach array methods */
if (clName.charAt(0) != '[') {
clName = clName.substring(1, clName.length()-1).replace('/', '.');
Main.getClassBundle().reachableIdentifier
(clName+"."+ref.getName()+"."+ref.getType(), isVirtual);
}
} }
public void handleClass(String clName) { public void handleClass(String clName) {
@ -479,7 +474,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
i++; i++;
if (i < clName.length() && clName.charAt(i) == 'L') { if (i < clName.length() && clName.charAt(i) == 'L') {
clName = clName.substring(i+1, clName.length()-1); clName = clName.substring(i+1, clName.length()-1);
Main.getClassBundle().reachableIdentifier(clName, false); Main.getClassBundle().reachableClass(clName);
} }
} }
@ -872,7 +867,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
if (local.value != ConstValue.VOLATILE) { if (local.value != ConstValue.VOLATILE) {
result = new ConstValue result = new ConstValue
(new Integer(((Integer)local.value).intValue() (new Integer(((Integer)local.value).intValue()
+ instr.getIntData())); + instr.getIncrement()));
local.addConstantListener(result); local.addConstantListener(result);
} else } else
result = unknownValue[0]; result = unknownValue[0];
@ -1072,7 +1067,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
if ((opc_mask & (1<<opcode)) != 0) if ((opc_mask & (1<<opcode)) != 0)
pc = instr.getSuccs()[0]; pc = instr.getSingleSucc();
ConstantInfo shortInfo = new ConstantInfo(); ConstantInfo shortInfo = new ConstantInfo();
constInfos.put(instr, shortInfo); constInfos.put(instr, shortInfo);
@ -1081,40 +1076,19 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
mergeInfo(pc, info.pop(size)); mergeInfo(pc, info.pop(size));
} else { } else {
mergeInfo(instr.getNextByAddr(), info.pop(size)); mergeInfo(instr.getNextByAddr(), info.pop(size));
mergeInfo(instr.getSuccs()[0], info.pop(size)); mergeInfo(instr.getSingleSucc(), info.pop(size));
} }
break; break;
} }
case opc_goto: case opc_goto:
mergeInfo(instr.getSuccs()[0], info.copy()); mergeInfo(instr.getSingleSucc(), info.copy());
break; break;
case opc_jsr: case opc_jsr:
mergeInfo(instr.getSuccs()[0], mergeInfo(instr.getSingleSucc(),
info.poppush(0, new ConstValue info.poppush(0, new ConstValue
(new JSRTargetInfo(instr.getSuccs()[0])))); (new JSRTargetInfo(instr.getSingleSucc()))
));
break; break;
case opc_tableswitch: {
ConstValue stacktop = info.getStack(1);
if (stacktop.value != ConstValue.VOLATILE) {
stacktop.addConstantListener(info);
Instruction pc;
int value = ((Integer) stacktop.value).intValue();
int low = instr.getIntData();
if (value >= low && value <= low + instr.getSuccs().length - 2)
pc = instr.getSuccs()[value - low];
else
pc = instr.getSuccs()[instr.getSuccs().length-1];
ConstantInfo shortInfo = new ConstantInfo();
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANTFLOW;
shortInfo.constant = pc;
mergeInfo(pc, info.pop(1));
} else {
for (int i=0; i < instr.getSuccs().length; i++)
mergeInfo(instr.getSuccs()[i], info.pop(1));
}
break;
}
case opc_lookupswitch: { case opc_lookupswitch: {
ConstValue stacktop = info.getStack(1); ConstValue stacktop = info.getStack(1);
if (stacktop.value != ConstValue.VOLATILE) { if (stacktop.value != ConstValue.VOLATILE) {
@ -1264,15 +1238,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
constant = false; constant = false;
if (jode.GlobalOptions.verboseLevel > 3) if (jode.GlobalOptions.verboseLevel > 3)
GlobalOptions.err.println("Can't interpret "+ref+": " GlobalOptions.err.println("Can't interpret "+ref+": "
+ ex.getMessage()); + ex.getMessage());
/* result is not constant */ /* result is not constant */
} catch (InvocationTargetException ex) { } catch (InvocationTargetException ex) {
constant = false; constant = false;
if (jode.GlobalOptions.verboseLevel > 3) if (jode.GlobalOptions.verboseLevel > 3)
GlobalOptions.err.println("Method "+ref GlobalOptions.err.println("Method "+ref
+" throwed exception: " +" throwed exception: "
+ ex.getTargetException() + ex.getTargetException());
.getMessage());
/* method always throws exception ? */ /* method always throws exception ? */
} }
} }
@ -1333,7 +1306,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_multianewarray: case opc_multianewarray:
handleClass(instr.getClazzType()); handleClass(instr.getClazzType());
mergeInfo(instr.getNextByAddr(), mergeInfo(instr.getNextByAddr(),
info.poppush(instr.getIntData(), unknownValue[0])); info.poppush(instr.getDimensions(), unknownValue[0]));
break; break;
default: default:
throw new jode.AssertError("Invalid opcode "+opcode); throw new jode.AssertError("Invalid opcode "+opcode);
@ -1342,8 +1315,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
public void fieldNotConstant(FieldIdentifier fi) { public void fieldNotConstant(FieldIdentifier fi) {
for (Instruction instr = bytecode.getFirstInstr(); for (Iterator iter = bytecode.getInstructions().iterator();
instr != null; instr = instr.getNextByAddr()) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_getfield if (instr.getOpcode() == opc_getfield
|| instr.getOpcode() == opc_getstatic) { || instr.getOpcode() == opc_getstatic) {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
@ -1357,8 +1331,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
public void dumpStackLocalInfo() { public void dumpStackLocalInfo() {
for (Instruction instr = bytecode.getFirstInstr(); for (Iterator iter = bytecode.getInstructions().iterator();
instr != null; instr = instr.getNextByAddr()) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo(); StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo();
System.err.println(""+info); System.err.println(""+info);
System.err.println(instr.getDescription()); System.err.println(instr.getDescription());
@ -1375,7 +1350,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
StackLocalInfo firstInfo = new StackLocalInfo StackLocalInfo firstInfo = new StackLocalInfo
(bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(), (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(),
modifiedQueue); modifiedQueue);
firstInfo.instr = bytecode.getFirstInstr(); firstInfo.instr = (Instruction) bytecode.getInstructions().get(0);
firstInfo.instr.setTmpInfo(firstInfo); firstInfo.instr.setTmpInfo(firstInfo);
modifiedQueue.add(firstInfo); modifiedQueue.add(firstInfo);
while (!modifiedQueue.isEmpty()) { while (!modifiedQueue.isEmpty()) {
@ -1389,35 +1364,43 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
for (int i=0; i< handlers.length; i++) { for (int i=0; i< handlers.length; i++) {
if (handlers[i].catcher.getTmpInfo() != null if (handlers[i].catcher.getTmpInfo() != null
&& handlers[i].type != null) && handlers[i].type != null)
Main.getClassBundle().reachableIdentifier(handlers[i].type, false); Main.getClassBundle().reachableClass(handlers[i].type);
} }
for (Instruction instr = bytecode.getFirstInstr(); for (Iterator iter = bytecode.getInstructions().iterator();
instr != null; instr = instr.getNextByAddr()) iter.hasNext(); )
instr.setTmpInfo(null); ((Instruction) iter.next()).setTmpInfo(null);
} }
public void insertOnePop(Instruction instr, int count) { public static void replaceWith(ListIterator iter, Instruction instr,
/* Add a goto instruction after this opcode. */ Instruction replacement) {
Instruction pop
= instr.insertInstruction(Instruction.opc_pop - 1 + count);
}
public void insertPop(Instruction instr) {
switch(instr.getOpcode()) { switch(instr.getOpcode()) {
case opc_goto:
case opc_ldc: case opc_ldc:
case opc_ldc2_w: case opc_ldc2_w:
case opc_iload: case opc_lload: case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload: case opc_fload: case opc_dload: case opc_aload:
case opc_getstatic: case opc_getstatic:
break; if (replacement == null)
iter.remove();
else
iter.set(replacement);
return;
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
case opc_ifnull: case opc_ifnonnull:
case opc_arraylength: case opc_arraylength:
case opc_getfield: case opc_getfield:
case opc_i2l: case opc_i2f: case opc_i2d: case opc_i2l: case opc_i2f: case opc_i2d:
case opc_f2i: case opc_f2l: case opc_f2d: case opc_f2i: case opc_f2l: case opc_f2d:
case opc_i2b: case opc_i2c: case opc_i2s: case opc_i2b: case opc_i2c: case opc_i2s:
case opc_ineg: case opc_fneg: case opc_ineg: case opc_fneg:
insertOnePop(instr, 1); iter.set(new Instruction(opc_pop));
break; break;
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_lcmp: case opc_lcmp:
case opc_dcmpg: case opc_dcmpl: case opc_dcmpg: case opc_dcmpl:
case opc_ladd: case opc_dadd: case opc_ladd: case opc_dadd:
@ -1426,7 +1409,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_ldiv: case opc_ddiv: case opc_ldiv: case opc_ddiv:
case opc_lrem: case opc_drem: case opc_lrem: case opc_drem:
case opc_land: case opc_lor : case opc_lxor: case opc_land: case opc_lor : case opc_lxor:
insertOnePop(instr, 2); iter.set(new Instruction(opc_pop2));
/* fall through */ /* fall through */
case opc_fcmpg: case opc_fcmpl: case opc_fcmpg: case opc_fcmpl:
case opc_l2i: case opc_l2f: case opc_l2d: case opc_l2i: case opc_l2f: case opc_l2d:
@ -1442,22 +1425,23 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_iaload: case opc_laload: case opc_iaload: case opc_laload:
case opc_faload: case opc_daload: case opc_aaload: case opc_faload: case opc_daload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload: case opc_baload: case opc_caload: case opc_saload:
insertOnePop(instr, 2); iter.set(new Instruction(opc_pop2));
break; break;
case opc_lshl: case opc_lshr: case opc_lushr: case opc_lshl: case opc_lshr: case opc_lushr:
insertOnePop(instr, 1); iter.set(new Instruction(opc_pop2));
insertOnePop(instr, 2); iter.add(new Instruction(opc_pop));
break; break;
case opc_putstatic: case opc_putstatic:
case opc_putfield: case opc_putfield:
if (Type.tType(instr.getReference().getType()) if (Type.tType(instr.getReference().getType())
.stackSize() == 2) { .stackSize() == 2) {
insertOnePop(instr, 2); iter.set(new Instruction(opc_pop2));
if (instr.getOpcode() == opc_putfield) if (instr.getOpcode() == opc_putfield)
insertOnePop(instr, 1); iter.add(new Instruction(opc_pop));
} else } else
insertOnePop(instr, (instr.getOpcode() == opc_putfield) ? 2 : 1); iter.set(new Instruction(instr.getOpcode() == opc_putfield
? opc_pop2 : opc_pop));
break; break;
case opc_invokespecial: case opc_invokespecial:
case opc_invokestatic: case opc_invokestatic:
@ -1465,34 +1449,52 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_invokevirtual: { case opc_invokevirtual: {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
MethodType mt = (MethodType) Type.tType(ref.getType()); MethodType mt = (MethodType) Type.tType(ref.getType());
for (int i=mt.getParameterTypes().length-1; i >=0; i--) Type[] pt = mt.getParameterTypes();
insertOnePop(instr, mt.getParameterTypes()[i].stackSize()); int arg = 0;
if (instr.getOpcode() != opc_invokestatic) if (instr.getOpcode() != opc_invokestatic)
insertOnePop(instr, 1); iter.set(new Instruction(opc_pop));
else if (pt.length > 0) {
iter.set(new Instruction(pt[0].stackSize() + opc_pop - 1));
arg++;
} else {
if (replacement == null)
iter.remove();
else
iter.set(replacement);
return;
}
for (int i=arg; i < pt.length; i++)
iter.add(new Instruction(pt[i].stackSize() + opc_pop - 1));
} }
} }
if (replacement != null)
iter.add(replacement);
} }
public void appendJump(Instruction instr, Instruction dest) { public void appendJump(ListIterator iter, Instruction dest) {
/* Add a goto instruction after this opcode. */ /* Add a goto instruction after this opcode. */
instr.appendInstruction(Instruction.opc_goto, Instruction gotoInstr = new Instruction(Instruction.opc_goto);
new Instruction[] { dest }); gotoInstr.setSuccs(dest);
iter.add(gotoInstr);
} }
public void transformCode(BytecodeInfo bytecode) { public void transformCode(BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr(); for (ListIterator iter = bytecode.getInstructions().listIterator();
instr != null; instr = instr.getNextByAddr()) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
ConstantInfo info = (ConstantInfo) constInfos.get(instr); ConstantInfo info = (ConstantInfo) constInfos.get(instr);
if (info == null || (info.flags & REACHABLE) == 0) { if (info == null || (info.flags & REACHABLE) == 0) {
/* This instruction can't be reached logically */ /* This instruction can't be reached logically */
instr.removeInstruction(); iter.remove();
} else if ((info.flags & CONSTANT) != 0) { } else if ((info.flags & CONSTANT) != 0) {
insertPop(instr);
if (instr.getOpcode() > opc_ldc2_w) { if (instr.getOpcode() > opc_ldc2_w) {
instr.replaceInstruction(info.constant instanceof Long Instruction ldcInstr
|| info.constant instanceof Double = new Instruction(info.constant instanceof Long
? opc_ldc2_w : opc_ldc); || info.constant instanceof Double
instr.setConstant(info.constant); ? opc_ldc2_w : opc_ldc);
ldcInstr.setConstant(info.constant);
replaceWith(iter, instr, ldcInstr);
if (GlobalOptions.verboseLevel > 2) if (GlobalOptions.verboseLevel > 2)
GlobalOptions.err.println GlobalOptions.err.println
(bytecode + ": Replacing " + instr (bytecode + ": Replacing " + instr
@ -1502,61 +1504,60 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
Instruction pc = (Instruction) info.constant; Instruction pc = (Instruction) info.constant;
if (instr.getOpcode() >= opc_if_icmpeq if (instr.getOpcode() >= opc_if_icmpeq
&& instr.getOpcode() <= opc_if_acmpne) && instr.getOpcode() <= opc_if_acmpne)
instr.replaceInstruction(opc_pop2); iter.set(new Instruction(opc_pop2));
else else
instr.replaceInstruction(opc_pop); iter.set(new Instruction(opc_pop));
if (GlobalOptions.verboseLevel > 2) if (GlobalOptions.verboseLevel > 2)
GlobalOptions.err.println GlobalOptions.err.println
(bytecode + ": Replacing " + instr (bytecode + ": Replacing " + instr
+ " with goto " + pc.getAddr()); + " with goto " + pc.getAddr());
while (instr.getNextByAddr() != null) { while (iter.hasNext()) {
ConstantInfo nextinfo ConstantInfo nextinfo = (ConstantInfo)
= (ConstantInfo) constInfos.get(instr.getNextByAddr()); constInfos.get((Instruction) iter.next());
if (nextinfo != null && (nextinfo.flags & REACHABLE) != 0) if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0) {
Instruction nextInstr = (Instruction) iter.previous();
if (pc != nextInstr)
appendJump(iter, pc);
break; break;
}
/* Next instruction can't be reached logically */ /* Next instruction can't be reached logically */
instr.getNextByAddr().removeInstruction(); iter.remove();
} }
if (pc != instr.getNextByAddr()) {
appendJump(instr, pc);
instr = instr.getNextByAddr();
}
} else { } else {
int opcode = instr.getOpcode(); int opcode = instr.getOpcode();
switch (opcode) { switch (opcode) {
case opc_nop: case opc_nop:
instr.removeInstruction(); iter.remove();
break; break;
case opc_goto: case opc_goto:
while (instr.getNextByAddr() != null) {
ConstantInfo nextinfo
= (ConstantInfo) constInfos.get(instr.getNextByAddr());
if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0)
break;
/* Next instruction can't be reached logically */
instr.getNextByAddr().removeInstruction();
}
if (instr.getSuccs()[0] == instr.getNextByAddr())
instr.removeInstruction();
break;
case opc_ifeq: case opc_ifne: case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge: case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle: case opc_ifgt: case opc_ifle:
case opc_ifnull: case opc_ifnonnull: case opc_ifnull: case opc_ifnonnull:
if (instr.getSuccs()[0] == instr.getNextByAddr())
instr.replaceInstruction(opc_pop);
break;
case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpeq: case opc_if_icmpne:
case opc_if_icmplt: case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmpge:
case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmpgt: case opc_if_icmple:
case opc_if_acmpeq: case opc_if_acmpne: case opc_if_acmpeq: case opc_if_acmpne:
if (instr.getSuccs()[0] == instr.getNextByAddr())
instr.replaceInstruction(opc_pop2); while (iter.hasNext()) {
ConstantInfo nextinfo = (ConstantInfo)
constInfos.get((Instruction) iter.next());
if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0) {
Instruction nextInstr
= (Instruction) iter.previous();
if (instr.getSingleSucc() == nextInstr) {
iter.previous();
replaceWith(iter, instr, null);
}
break;
}
/* Next instruction can't be reached logically */
iter.remove();
}
break; break;
case opc_putstatic: case opc_putstatic:
@ -1567,8 +1568,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
if (fi != null if (fi != null
&& (Main.stripping & Main.STRIP_UNREACH) != 0 && (Main.stripping & Main.STRIP_UNREACH) != 0
&& !fi.isReachable()) { && !fi.isReachable()) {
insertPop(instr); replaceWith(iter, instr, null);
instr.removeInstruction();
} }
break; break;
} }

@ -65,8 +65,8 @@ public class FieldIdentifier extends Identifier{
int index = type.indexOf('L'); int index = type.indexOf('L');
if (index != -1) { if (index != -1) {
int end = type.indexOf(';', index); int end = type.indexOf(';', index);
Main.getClassBundle().reachableIdentifier Main.getClassBundle().reachableClass
(type.substring(index+1, end), false); (type.substring(index+1, end).replace('/', '.'));
} }
} }
@ -75,11 +75,12 @@ public class FieldIdentifier extends Identifier{
} }
public String getFullName() { public String getFullName() {
return clazz.getFullName() + "." + getName(); return clazz.getFullName() + "." + getName() + "." + getType();
} }
public String getFullAlias() { public String getFullAlias() {
return clazz.getFullAlias() + "." + getAlias(); return clazz.getFullAlias() + "." + getAlias() + "."
+ Main.getClassBundle().getTypeAlias(getType());
} }
public String getName() { public String getName() {
@ -120,20 +121,7 @@ public class FieldIdentifier extends Identifier{
} }
public String toString() { public String toString() {
return "FieldIdentifier "+getFullName()+"."+getType(); return "FieldIdentifier "+getFullName();
}
public void readTable(Map table) {
String alias = (String) table.get(getFullName() + "." + getType());
if (alias == null)
alias = (String) table.get(getFullName());
if (alias != null)
setAlias(alias);
}
public void writeTable(Map table) {
table.put(getFullAlias() + "."
+ Main.getClassBundle().getTypeAlias(getType()), getName());
} }
public boolean conflicting(String newAlias) { public boolean conflicting(String newAlias) {

@ -20,10 +20,12 @@
package jode.obfuscator; package jode.obfuscator;
import java.util.*; import java.util.*;
import jode.bytecode.*; import jode.bytecode.*;
import jode.type.Type;
import jode.AssertError; import jode.AssertError;
import jode.GlobalOptions; import jode.GlobalOptions;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
/** /**
* This class takes some bytecode and tries to minimize the number * This class takes some bytecode and tries to minimize the number
* of locals used. It will also remove unnecessary stores. * of locals used. It will also remove unnecessary stores.
@ -221,14 +223,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
BitSet mergeSet, boolean inverted) { BitSet mergeSet, boolean inverted) {
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr); InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr);
int omitLocal = -1; int omitLocal = -1;
if (preInstr.getLocalSlot() != -1 if (preInstr.getOpcode() >= opc_istore
&& preInstr.getOpcode() >= opc_istore
&& preInstr.getOpcode() <= opc_astore) { && preInstr.getOpcode() <= opc_astore) {
/* This is a store */ /* This is a store */
omitLocal = preInstr.getLocalSlot(); omitLocal = preInstr.getLocalSlot();
if (info.nextReads[preInstr.getLocalSlot()] != null) if (info.nextReads[omitLocal] != null)
preInfo.local.combineInto preInfo.local.combineInto(info.nextReads[omitLocal].local);
(info.nextReads[preInstr.getLocalSlot()].local);
} }
for (int i=0; i < maxlocals; i++) { for (int i=0; i < maxlocals; i++) {
if (info.nextReads[i] != null && i != omitLocal if (info.nextReads[i] != null && i != omitLocal
@ -270,10 +270,12 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
Instruction instr) { Instruction instr) {
int addr = instr.getAddr(); int addr;
if (instr.getOpcode() >= opc_istore if (instr.getOpcode() >= opc_istore
&& instr.getOpcode() <= opc_astore) && instr.getOpcode() <= opc_astore)
addr += instr.getLength(); addr = instr.getNextAddr();
else
addr = instr.getAddr();
return findLVTEntry(lvt, instr.getLocalSlot(), addr); return findLVTEntry(lvt, instr.getLocalSlot(), addr);
} }
@ -286,11 +288,9 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
/* Initialize paramLocals */ /* Initialize paramLocals */
{ {
int paramCount = bc.getMethodInfo().isStatic() ? 0 : 1; String methodType = bc.getMethodInfo().getType();
Type[] paramTypes = int paramCount = (bc.getMethodInfo().isStatic() ? 0 : 1)
Type.tMethod(bc.getMethodInfo().getType()).getParameterTypes(); + TypeSignature.getArgumentSize(methodType);
for (int i = paramTypes.length; i-- > 0;)
paramCount += paramTypes[i].stackSize();
paramLocals = new LocalInfo[paramCount]; paramLocals = new LocalInfo[paramCount];
int slot = 0; int slot = 0;
if (!bc.getMethodInfo().isStatic()) { if (!bc.getMethodInfo().isStatic()) {
@ -305,7 +305,10 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
local.size = 1; local.size = 1;
paramLocals[slot++] = local; paramLocals[slot++] = local;
} }
for (int i = 0; i< paramTypes.length; i++) { int pos = 1;
while (pos < methodType.length()
&& methodType.charAt(pos) != ')') {
LocalInfo local = new LocalInfo(); LocalInfo local = new LocalInfo();
if (lvt != null) { if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0); LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0);
@ -313,8 +316,11 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
local.name = lvi.name; local.name = lvi.name;
} }
} }
local.type = paramTypes[i].getTypeSignature();
local.size = paramTypes[i].stackSize(); int start = pos;
pos = TypeSignature.skipType(methodType, pos);
local.type = methodType.substring(start, pos);
local.size = TypeSignature.getTypeSize(local.type);
paramLocals[slot] = local; paramLocals[slot] = local;
slot += local.size; slot += local.size;
} }
@ -326,12 +332,13 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
instrInfos = new Hashtable(); instrInfos = new Hashtable();
{ {
InstrInfo info = firstInfo = new InstrInfo(); InstrInfo info = firstInfo = new InstrInfo();
Instruction instr = bc.getFirstInstr(); Iterator i = bc.getInstructions().iterator();
while (true) { while (true) {
Instruction instr = (Instruction) i.next();
instrInfos.put(instr, info); instrInfos.put(instr, info);
info.instr = instr; info.instr = instr;
info.nextReads = new InstrInfo[maxlocals]; info.nextReads = new InstrInfo[maxlocals];
if (instr.getLocalSlot() != -1) { if (instr.hasLocalSlot()) {
info.local = new LocalInfo(info); info.local = new LocalInfo(info);
if (lvt != null) { if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, instr); LocalVariableInfo lvi = findLVTEntry(lvt, instr);
@ -364,7 +371,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
//case opc_istore: case opc_fstore: case opc_astore: //case opc_istore: case opc_fstore: case opc_astore:
} }
} }
if ((instr = instr.getNextByAddr()) == null) if (!i.hasNext())
break; break;
info = info.nextInfo = new InstrInfo(); info = info.nextInfo = new InstrInfo();
} }
@ -377,16 +384,17 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
Instruction instr = info.instr; Instruction instr = info.instr;
/* Mark the local as used in all ret instructions */ /* Mark the local as used in all ret instructions */
if (instr.getLocalSlot() != -1) { if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
for (int i=0; i< maxlocals; i++) { for (int i=0; i< maxlocals; i++) {
InstrInfo retInfo = info.nextReads[i]; InstrInfo retInfo = info.nextReads[i];
if (retInfo != null && retInfo.instr.getOpcode() == opc_ret if (retInfo != null
&& !retInfo.usedBySub.get(instr.getLocalSlot())) { && retInfo.instr.getOpcode() == opc_ret
retInfo.usedBySub.set(instr.getLocalSlot()); && !retInfo.usedBySub.get(slot)) {
retInfo.usedBySub.set(slot);
if (retInfo.jsrTargetInfo != null) if (retInfo.jsrTargetInfo != null)
changedInfos.push(retInfo.jsrTargetInfo); changedInfos.push(retInfo.jsrTargetInfo);
} }
} }
} }
@ -397,7 +405,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
* corresponding ret. * corresponding ret.
*/ */
InstrInfo jsrInfo = InstrInfo jsrInfo =
(InstrInfo) instrInfos.get(prevInstr.getSuccs()[0]); (InstrInfo) instrInfos.get(prevInstr.getSingleSucc());
if (jsrInfo.retInfo != null) { if (jsrInfo.retInfo != null) {
/* Now promote reads that are modified by the /* Now promote reads that are modified by the
* subroutine to the ret, and those that are not * subroutine to the ret, and those that are not
@ -426,8 +434,8 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
* local. */ * local. */
throw new AssertError("Non standard jsr"); throw new AssertError("Non standard jsr");
} }
InstrInfo retInfo InstrInfo retInfo = info.nextInfo.nextReads
= info.nextInfo.nextReads[info.instr.getLocalSlot()]; [info.instr.getLocalSlot()];
if (retInfo != null) { if (retInfo != null) {
if (retInfo.instr.getOpcode() != opc_ret) if (retInfo.instr.getOpcode() != opc_ret)
@ -481,21 +489,21 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
} }
public void stripLocals() { public void stripLocals() {
ListIterator iter = bc.getInstructions().listIterator();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
Instruction instr = (Instruction) iter.next();
if (info.local != null && info.local.usingInstrs.size() == 1) { if (info.local != null && info.local.usingInstrs.size() == 1) {
/* If this is a store, whose value is never read; it can /* If this is a store, whose value is never read; it can
* be removed, i.e replaced by a pop. */ * be removed, i.e replaced by a pop. */
switch (info.instr.getOpcode()) { switch (instr.getOpcode()) {
case opc_istore: case opc_istore:
case opc_fstore: case opc_fstore:
case opc_astore: case opc_astore:
info.local = null; iter.set(new Instruction(opc_pop));
info.instr.replaceInstruction(opc_pop);
break; break;
case opc_lstore: case opc_lstore:
case opc_dstore: case opc_dstore:
info.local = null; iter.set(new Instruction(opc_pop2));
info.instr.replaceInstruction(opc_pop);
break; break;
default: default:
} }
@ -568,8 +576,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
/* Now calculate the conflict settings. /* Now calculate the conflict settings.
*/ */
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.instr.getLocalSlot() != -1 if (info.instr.getOpcode() >= BytecodeInfo.opc_istore
&& info.instr.getOpcode() >= BytecodeInfo.opc_istore
&& info.instr.getOpcode() <= BytecodeInfo.opc_astore) { && info.instr.getOpcode() <= BytecodeInfo.opc_astore) {
/* This is a store. It conflicts with every local, whose /* This is a store. It conflicts with every local, whose
* value will be read without write. * value will be read without write.
@ -692,13 +699,14 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
InstrInfo info = (InstrInfo) changedInfo.pop(); InstrInfo info = (InstrInfo) changedInfo.pop();
Instruction instr = info.instr; Instruction instr = info.instr;
LocalInfo[] newLife = info.lifeLocals; LocalInfo[] newLife = info.lifeLocals;
if (instr.getLocalSlot() != -1) { if (instr.hasLocalSlot()) {
int slot = instr.getLocalSlot();
LocalInfo instrLocal = info.local.getReal(); LocalInfo instrLocal = info.local.getReal();
newLife = (LocalInfo[]) newLife.clone(); newLife = (LocalInfo[]) newLife.clone();
newLife[instr.getLocalSlot()] = instrLocal; newLife[slot] = instrLocal;
if (instrLocal.name != null) { if (instrLocal.name != null) {
for (int j=0; j< newLife.length; j++) { for (int j=0; j< newLife.length; j++) {
if (j != instr.getLocalSlot() if (j != slot
&& newLife[j] != null && newLife[j] != null
&& instrLocal.name.equals(newLife[j].name)) { && instrLocal.name.equals(newLife[j].name)) {
/* This local changed the slot. */ /* This local changed the slot. */
@ -713,17 +721,18 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
if (promoteLifeLocals(newLife, nextInfo)) if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo); changedInfo.push(nextInfo);
} }
if (instr.getSuccs() != null) { if (instr.hasSuccs()) {
for (int i = 0; i < instr.getSuccs().length; i++) { Instruction[] succs = instr.getSuccs();
for (int i = 0; i < succs.length; i++) {
InstrInfo nextInfo InstrInfo nextInfo
= (InstrInfo) instrInfos.get(instr.getSuccs()[i]); = (InstrInfo) instrInfos.get(succs[i]);
if (promoteLifeLocals(newLife, nextInfo)) if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo); changedInfo.push(nextInfo);
} }
} }
for (int i=0; i < handlers.length; i++) { for (int i=0; i < handlers.length; i++) {
if (handlers[i].start.getAddr() <= instr.getAddr() if (handlers[i].start.compareTo(instr) <= 0
&& handlers[i].end.getAddr() >= instr.getAddr()) { && handlers[i].end.compareTo(instr) >= 0) {
InstrInfo nextInfo InstrInfo nextInfo
= (InstrInfo) instrInfos.get(handlers[i].catcher); = (InstrInfo) instrInfos.get(handlers[i].catcher);
if (promoteLifeLocals(newLife, nextInfo)) if (promoteLifeLocals(newLife, nextInfo))
@ -734,7 +743,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
if (info.instr.getOpcode() == opc_jsr) { if (info.instr.getOpcode() == opc_jsr) {
/* On a jsr we do a special merge */ /* On a jsr we do a special merge */
Instruction jsrTargetInstr = info.instr.getSuccs()[0]; Instruction jsrTargetInstr = info.instr.getSingleSucc();
InstrInfo jsrTargetInfo InstrInfo jsrTargetInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr); = (InstrInfo) instrInfos.get(jsrTargetInstr);
InstrInfo retInfo = jsrTargetInfo.retInfo; InstrInfo retInfo = jsrTargetInfo.retInfo;
@ -783,7 +792,7 @@ public class LocalOptimizer implements Opcodes, CodeTransformer {
lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */ lvi[i].name = currentLocal[i].name; /* XXX obfuscation? */
lvi[i].type = Main.getClassBundle() lvi[i].type = Main.getClassBundle()
.getTypeAlias(currentLocal[i].type); .getTypeAlias(currentLocal[i].type);
lvi[i].start = bc.getFirstInstr(); lvi[i].start = (Instruction) bc.getInstructions().get(0);
lvi[i].slot = i; lvi[i].slot = i;
} }
} }

@ -34,6 +34,7 @@ MY_JAVA_FILES = \
SimpleAnalyzer.java \ SimpleAnalyzer.java \
StrongRenamer.java \ StrongRenamer.java \
TranslationTable.java \ TranslationTable.java \
UniqueRenamer.java \
WildCard.java WildCard.java
# LocalizeFieldTransformer.java # LocalizeFieldTransformer.java

@ -88,9 +88,8 @@ public class MethodIdentifier extends Identifier implements Opcodes {
int index = type.indexOf('L'); int index = type.indexOf('L');
while (index != -1) { while (index != -1) {
int end = type.indexOf(';', index); int end = type.indexOf(';', index);
Main.getClassBundle() Main.getClassBundle().reachableClass
.reachableIdentifier(type.substring(index+1, end) (type.substring(index+1, end).replace('/', '.'));
, false);
index = type.indexOf('L', end); index = type.indexOf('L', end);
} }
@ -98,7 +97,7 @@ public class MethodIdentifier extends Identifier implements Opcodes {
if (exceptions != null) { if (exceptions != null) {
for (int i=0; i< exceptions.length; i++) for (int i=0; i< exceptions.length; i++)
Main.getClassBundle() Main.getClassBundle()
.reachableIdentifier(exceptions[i], false); .reachableClass(exceptions[i]);
} }
BytecodeInfo code = info.getBytecode(); BytecodeInfo code = info.getBytecode();
@ -106,14 +105,6 @@ public class MethodIdentifier extends Identifier implements Opcodes {
codeAnalyzer.analyzeCode(this, code); codeAnalyzer.analyzeCode(this, code);
} }
public void readTable(Map table) {
setAlias((String) table.get(getFullName() + "." + getType()));
}
public void writeTable(Map table) {
table.put(getFullAlias(), getName());
}
public Identifier getParent() { public Identifier getParent() {
return clazz; return clazz;
} }
@ -140,7 +131,7 @@ public class MethodIdentifier extends Identifier implements Opcodes {
} }
public String toString() { public String toString() {
return "MethodIdentifier "+getFullName()+"."+getType(); return "MethodIdentifier "+getFullName();
} }
public boolean hasGlobalSideEffects() { public boolean hasGlobalSideEffects() {
@ -187,9 +178,10 @@ public class MethodIdentifier extends Identifier implements Opcodes {
ex.printStackTrace(GlobalOptions.err); ex.printStackTrace(GlobalOptions.err);
bytecode.dumpCode(GlobalOptions.err); bytecode.dumpCode(GlobalOptions.err);
} }
for (Instruction instr = bytecode.getFirstInstr(); for (Iterator iter = bytecode.getInstructions().iterator();
instr != null; instr = instr.getNextByAddr()) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
switch (instr.getOpcode()) { switch (instr.getOpcode()) {
case opc_invokespecial: case opc_invokespecial:
case opc_invokestatic: case opc_invokestatic:

@ -64,44 +64,32 @@ public class PackageIdentifier extends Identifier {
return; return;
loadOnDemand = true; loadOnDemand = true;
if ((Main.stripping & Main.STRIP_UNREACH) == 0) { if ((Main.stripping & Main.STRIP_UNREACH) == 0) {
String fullname = getFullName();
if (fullname.length() > 0)
fullname += ".";
// Load all classes and packages now, so they don't get stripped // Load all classes and packages now, so they don't get stripped
Vector v = new Vector();
Enumeration enum = Enumeration enum =
ClassInfo.getClassesAndPackages(getFullName()); ClassInfo.getClassesAndPackages(getFullName());
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
//insert sorted and remove double elements; String subclazz = ((String)enum.nextElement()).intern();
String subclazz = (String)enum.nextElement(); if (loadedClasses.containsKey(subclazz))
for (int i=0; ; i++) { continue;
if (i == v.size()) { String subFull = fullname + subclazz;
v.addElement(subclazz);
break; if (ClassInfo.isPackage(subFull)) {
}
int compare = subclazz.compareTo((String)v.elementAt(i));
if (compare < 0) {
v.insertElementAt(subclazz, i);
break;
} else if (compare == 0)
break;
}
}
enum = v.elements();
while (enum.hasMoreElements()) {
String subclazz = (String) enum.nextElement();
String fullname = getFullName();
fullname = (fullname.length() > 0)
? fullname + "."+ subclazz
: subclazz;
if (ClassInfo.isPackage(fullname)) {
PackageIdentifier ident = new PackageIdentifier PackageIdentifier ident = new PackageIdentifier
(bundle, this, subclazz); (bundle, this, subclazz);
loadedClasses.put(subclazz, ident); loadedClasses.put(subclazz, ident);
ident.setLoadOnDemand(); ident.setLoadOnDemand();
} else { } else {
Identifier ident = new ClassIdentifier ClassIdentifier ident = new ClassIdentifier
(this, subclazz, ClassInfo.forName(fullname)); (this, subclazz, ClassInfo.forName(subFull));
if (GlobalOptions.verboseLevel > 1)
GlobalOptions.err.println("preloading Class "
+ subFull);
loadedClasses.put(subclazz, ident); loadedClasses.put(subclazz, ident);
if (GlobalOptions.verboseLevel > 0)
GlobalOptions.err.println("preloading "+ident);
((ClassIdentifier) ident).initClass(); ((ClassIdentifier) ident).initClass();
} }
} }
@ -184,6 +172,7 @@ public class PackageIdentifier extends Identifier {
if (component != null) { if (component != null) {
Identifier ident = (Identifier) loadedClasses.get(component); Identifier ident = (Identifier) loadedClasses.get(component);
if (ident == null) { if (ident == null) {
component = component.intern();
String fullname = getFullName(); String fullname = getFullName();
fullname = (fullname.length() > 0) fullname = (fullname.length() > 0)
? fullname + "." + component ? fullname + "." + component
@ -227,7 +216,7 @@ public class PackageIdentifier extends Identifier {
Enumeration enum = Enumeration enum =
ClassInfo.getClassesAndPackages(getFullName()); ClassInfo.getClassesAndPackages(getFullName());
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
String subclazz = (String)enum.nextElement(); String subclazz = ((String)enum.nextElement()).intern();
if (loadedClasses.containsKey(subclazz)) if (loadedClasses.containsKey(subclazz))
continue; continue;
String subFull = fullname + subclazz; String subFull = fullname + subclazz;
@ -276,36 +265,6 @@ public class PackageIdentifier extends Identifier {
loadMatchingClasses(preserveRule); loadMatchingClasses(preserveRule);
super.applyPreserveRule(preserveRule); super.applyPreserveRule(preserveRule);
} }
public void reachableIdentifier(String fqn, boolean isVirtual) {
int index = fqn.indexOf('.');
String component = index == -1 ? fqn : fqn.substring(0, index);
Identifier ident = getIdentifier(component);
if (ident == null)
return;
if (index == -1) {
ident.setReachable();
return;
}
if (ident instanceof PackageIdentifier)
((PackageIdentifier) ident).reachableIdentifier
(fqn.substring(index+1), isVirtual);
else {
String method = fqn.substring(index+1);
index = method.indexOf('.');
if (index == -1) {
((ClassIdentifier) ident).reachableIdentifier
(method, null, isVirtual);
} else {
((ClassIdentifier) ident).reachableIdentifier
(method.substring(0, index), method.substring(index+1),
isVirtual);
}
}
}
// public void preserveMatchingIdentifier(IdentifierMatcher matcher) { // public void preserveMatchingIdentifier(IdentifierMatcher matcher) {
// String component = matcher.getNextComponent(getFullName()); // String component = matcher.getNextComponent(getFullName());
// if (component != null) { // if (component != null) {

@ -1,262 +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;
public class RemovePopAnalyzer implements CodeTransformer, Opcodes {
public RemovePopAnalyzer() {
}
class PopInfo {
int firstPop = 0;
int[] pops;
Instruction nextInstr;
}
static Instruction shrinkPop(Instruction popInstr, int amount) {
int newPop = popInstr.getOpcode() - (opc_pop-1) - amount;
if (newPop < 0)
throw new jode.AssertError("pop1 on long or double");
if (newPop == 0) {
Instruction nextInstr = popInstr.getNextByAddr();
popInstr.removeInstruction();
return nextInstr;
}
popInstr.replaceInstruction(opc_pop - 1 + newPop);
return popInstr;
}
public void transformCode(BytecodeInfo bytecode) {
int poppush[] = new int[2];
Instruction instr = bytecode.getFirstInstr();
while (instr != null) {
switch (instr.getOpcode()) {
case opc_nop: {
Instruction nextInstr = instr.getNextByAddr();
instr.removeInstruction();
instr = nextInstr;
continue;
}
case opc_pop:
case opc_pop2: {
/* find push instruction */
int count = 0;
Instruction pushInstr = instr;
while (true) {
if (pushInstr.getPreds() != null) {
pushInstr = null;
break;
}
pushInstr = pushInstr.getPrevByAddr();
if (pushInstr == null
|| pushInstr.getSuccs() != null
|| pushInstr.doesAlwaysJump()) {
pushInstr = null;
break;
}
pushInstr.getStackPopPush(poppush);
if (count < poppush[1])
break;
count += poppush[0] - poppush[1];
}
int opcode = pushInstr == null ? -1 : pushInstr.getOpcode();
if (count > 0) {
/* If this is a dup and the instruction popped is the
* duplicated element, remove the dup
*/
if (count <= 2 && opcode == (opc_dup + count - 1)) {
pushInstr.removeInstruction();
instr = shrinkPop(instr, 1);
continue;
}
if (instr.getOpcode() == opc_pop2
&& count > 1 && count <= 3
&& opcode == (opc_dup2 + count-2)) {
pushInstr.removeInstruction();
instr = shrinkPop(instr, 2);
continue;
}
/* Otherwise popping is not possible */
opcode = -1;
}
switch (opcode) {
case opc_ldc2_w:
case opc_lload: case opc_dload:
pushInstr.removeInstruction();
instr = shrinkPop(instr, 2);
continue;
case opc_ldc:
case opc_iload: case opc_fload: case opc_aload:
case opc_dup:
case opc_new:
pushInstr.removeInstruction();
instr = shrinkPop(instr, 1);
continue;
case opc_iaload: case opc_faload: case opc_aaload:
case opc_baload: case opc_caload: case opc_saload:
/* We have to pop one entry more. */
pushInstr.replaceInstruction(opc_pop);
instr = pushInstr;
continue;
case opc_dup_x1:
pushInstr.replaceInstruction(opc_swap);
instr = shrinkPop(instr, 1);
continue;
case opc_dup2:
if (instr.getOpcode() == opc_pop2) {
pushInstr.removeInstruction();
instr = shrinkPop(instr, 2);
}
continue;
case opc_lneg: case opc_dneg:
case opc_l2d: case opc_d2l:
case opc_laload: case opc_daload:
if (instr.getOpcode() != opc_pop2)
break;
/* 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:
pushInstr.removeInstruction();
continue;
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:
case opc_l2i: case opc_l2f:
case opc_d2i: case opc_d2f:
pushInstr.replaceInstruction(opc_pop2);
shrinkPop(instr, 1);
instr = pushInstr;
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 (instr.getOpcode() != opc_pop2)
break;
pushInstr.replaceInstruction(opc_pop2);
instr = pushInstr;
continue;
case opc_lshl: case opc_lshr: case opc_lushr:
if (instr.getOpcode() != opc_pop2)
break;
pushInstr.replaceInstruction(opc_pop);
instr = pushInstr;
continue;
case opc_i2l: case opc_i2d:
case opc_f2l: case opc_f2d:
if (instr.getOpcode() != opc_pop2)
break;
pushInstr.removeInstruction();
instr.replaceInstruction(opc_pop);
continue;
case opc_lcmp:
case opc_dcmpl: case opc_dcmpg:
pushInstr.replaceInstruction(opc_pop2);
if (instr.getOpcode() == opc_pop)
instr.replaceInstruction(opc_pop2);
else {
instr.appendInstruction(opc_pop);
}
instr = pushInstr;
continue;
case opc_getstatic:
case opc_getfield: {
Reference ref = pushInstr.getReference();
int size = TypeSignature.getTypeSize(ref.getType());
if (pushInstr.getOpcode() == opc_getfield)
size--;
pushInstr.removeInstruction();
if (size > 0)
instr = shrinkPop(instr, size);
continue;
}
case opc_multianewarray: {
int dims = pushInstr.getIntData();
pushInstr.removeInstruction();
if (dims == 0)
instr = shrinkPop(instr, 1);
else {
dims--;
while (dims > 0) {
instr = instr.insertInstruction(opc_pop);
dims--;
}
}
continue;
}
case opc_invokevirtual:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
if (TypeSignature.getReturnSize
(pushInstr.getReference().getType()) != 1)
break;
/* fall through */
case opc_checkcast:
case -1:
if (instr.getOpcode() == opc_pop2) {
/* This is/may be a double pop on a single value
* split it and continue with second half
*/
instr.replaceInstruction(opc_pop);
instr = instr.appendInstruction(opc_pop);
continue;
}
}
if (instr.getOpcode() == opc_pop
&& instr.getPreds() == null
&& instr.getPrevByAddr().getOpcode() == opc_pop) {
/* merge two single pops together. */
instr.getPrevByAddr().removeInstruction();
instr.replaceInstruction(opc_pop2);
}
/* Cant do anything with this pop */
}
/* fall through */
default:
instr = instr.getNextByAddr();
continue;
}
}
}
}

@ -0,0 +1,307 @@
/* 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;
}
}
}
}

@ -251,7 +251,9 @@ public class ScriptParser {
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw new ParseException(linenr, throw new ParseException(linenr,
optionHandler.getClass().getName() optionHandler.getClass().getName()
+": Illegal value: "+ex.getMessage()); +": Illegal value: "
+ex.getClass().getName()
+": "+ex.getMessage());
} }
} }
} }

@ -27,6 +27,9 @@ import jode.bytecode.Reference;
import jode.GlobalOptions; import jode.GlobalOptions;
import jode.type.Type; import jode.type.Type;
import @COLLECTIONS@.Iterator;
import @COLLECTIONS@.ListIterator;
public class SimpleAnalyzer implements CodeAnalyzer, Opcodes { public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
public Identifier canonizeReference(Instruction instr) { public Identifier canonizeReference(Instruction instr) {
@ -87,8 +90,9 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
* @return an enumeration of the references. * @return an enumeration of the references.
*/ */
public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) { public void analyzeCode(MethodIdentifier m, BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr(); for (Iterator iter = bytecode.getInstructions().iterator();
instr != null; instr = instr.getNextByAddr()) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
switch (instr.getOpcode()) { switch (instr.getOpcode()) {
case opc_checkcast: case opc_checkcast:
case opc_instanceof: case opc_instanceof:
@ -98,8 +102,9 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
while (i < clName.length() && clName.charAt(i) == '[') while (i < clName.length() && clName.charAt(i) == '[')
i++; i++;
if (i < clName.length() && clName.charAt(i) == 'L') { if (i < clName.length() && clName.charAt(i) == 'L') {
clName = clName.substring(i+1, clName.length()-1); clName = clName.substring(i+1, clName.length()-1)
Main.getClassBundle().reachableIdentifier(clName, false); .replace('/','.');
Main.getClassBundle().reachableClass(clName);
} }
break; break;
} }
@ -123,8 +128,7 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
} else if (instr.getOpcode() == opc_invokevirtual } else if (instr.getOpcode() == opc_invokevirtual
|| instr.getOpcode() == opc_invokeinterface) { || instr.getOpcode() == opc_invokeinterface) {
((ClassIdentifier) ident.getParent()) ((ClassIdentifier) ident.getParent())
.reachableIdentifier(ident.getName(), .reachableReference(instr.getReference(), true);
ident.getType(), true);
} else { } else {
ident.setReachable(); ident.setReachable();
} }
@ -138,13 +142,14 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
for (int i=0; i< handlers.length; i++) { for (int i=0; i< handlers.length; i++) {
if (handlers[i].type != null) if (handlers[i].type != null)
Main.getClassBundle() Main.getClassBundle()
.reachableIdentifier(handlers[i].type, false); .reachableClass(handlers[i].type);
} }
} }
public void transformCode(BytecodeInfo bytecode) { public void transformCode(BytecodeInfo bytecode) {
for (Instruction instr = bytecode.getFirstInstr(); for (ListIterator iter = bytecode.getInstructions().listIterator();
instr != null; instr = instr.getNextByAddr()) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
if (instr.getOpcode() == opc_putstatic if (instr.getOpcode() == opc_putstatic
|| instr.getOpcode() == opc_putfield) { || instr.getOpcode() == opc_putfield) {
Reference ref = instr.getReference(); Reference ref = instr.getReference();
@ -158,13 +163,18 @@ public class SimpleAnalyzer implements CodeAnalyzer, Opcodes {
(instr.getOpcode() (instr.getOpcode()
== Instruction.opc_putstatic) ? 0 : 1; == Instruction.opc_putstatic) ? 0 : 1;
stacksize += Type.tType(ref.getType()).stackSize(); stacksize += Type.tType(ref.getType()).stackSize();
if (stacksize == 3) { switch (stacksize) {
/* Add a pop instruction after this opcode. */ case 1:
instr.appendInstruction(Instruction.opc_pop); iter.set(new Instruction(Instruction.opc_pop));
stacksize--; 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;
} }
instr.replaceInstruction(Instruction.opc_pop - 1
+ stacksize);
} }
} }
} }

@ -1,6 +1,7 @@
package jode.obfuscator; package jode.obfuscator;
import @COLLECTIONS@.Iterator; import @COLLECTIONS@.Iterator;
import @COLLECTIONEXTRA@.UnsupportedOperationException;
public class UniqueRenamer implements Renamer { public class UniqueRenamer implements Renamer {
static int serialnr = 0; static int serialnr = 0;

Loading…
Cancel
Save