Interpret method with constant args

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@542 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 42dfa8092d
commit c8b176e899
  1. 120
      jode/jode/obfuscator/ConstantAnalyzer.java

@ -19,11 +19,14 @@
package jode.obfuscator; package jode.obfuscator;
import jode.MethodType; import jode.MethodType;
import jode.Obfuscator;
import jode.Type; import jode.Type;
import jode.bytecode.*; import jode.bytecode.*;
import jode.jvm.InterpreterException;
import java.util.*; import java.util.*;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
interface ConstantListener { interface ConstantListener {
public void constantChanged(); public void constantChanged();
@ -120,6 +123,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
BytecodeInfo bytecode; BytecodeInfo bytecode;
Hashtable constInfos = null; Hashtable constInfos = null;
Stack instrStack; Stack instrStack;
ConstantRuntimeEnvironment runtime;
final static int REACHABLE = 0x1; final static int REACHABLE = 0x1;
final static int CONSTANT = 0x2; final static int CONSTANT = 0x2;
@ -261,6 +265,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
public ConstantAnalyzer(BytecodeInfo code, MethodIdentifier method) { public ConstantAnalyzer(BytecodeInfo code, MethodIdentifier method) {
this.bytecode = code; this.bytecode = code;
this.m = method; this.m = method;
this.runtime = new ConstantRuntimeEnvironment(m);
} }
public void mergeInfo(Instruction instr, public void mergeInfo(Instruction instr,
@ -968,20 +973,75 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_invokeinterface: case opc_invokeinterface:
case opc_invokevirtual: { case opc_invokevirtual: {
Reference ref = (Reference) instr.objData; Reference ref = (Reference) instr.objData;
handleReference(ref, opcode == opc_invokevirtual
|| opcode == opc_invokeinterface);
MethodType mt = (MethodType) Type.tType(ref.getType()); MethodType mt = (MethodType) Type.tType(ref.getType());
int size = (opcode == opc_invokestatic) ? 0 : 1; boolean constant = true;
for (int i=mt.getParameterTypes().length-1; i >=0; i--) int size = 0;
Object cls = null;
Object[] args = new Object[mt.getParameterTypes().length];
ConstantAnalyzerValue clsValue = null;
ConstantAnalyzerValue[] argValues =
new ConstantAnalyzerValue[mt.getParameterTypes().length];
for (int i=mt.getParameterTypes().length-1; i >=0; i--) {
size += mt.getParameterTypes()[i].stackSize(); size += mt.getParameterTypes()[i].stackSize();
ConstantAnalyzerInfo newInfo; argValues[i] = info.getStack(size);
if (mt.getReturnType() != Type.tVoid) { if (argValues[i].value != ConstantAnalyzerValue.VOLATILE)
ConstantAnalyzerValue returnVal = args[i] = argValues[i].value;
else
constant = false;
}
if (opcode != opc_invokestatic) {
size++;
clsValue = info.getStack(size);
cls = clsValue.value;
if (cls == ConstantAnalyzerValue.VOLATILE
|| cls == null)
constant = false;
}
if (mt.getReturnType() == Type.tVoid) {
handleReference(ref, opcode == opc_invokevirtual
|| opcode == opc_invokeinterface);
mergeInfo(instr.nextByAddr, info.pop(size));
break;
}
Object methodResult = null;
if (constant) {
try {
if (jode.Obfuscator.isDebugging)
jode.Decompiler.isDebugging = true; /*XXX*/
methodResult = runtime.invokeMethod
(ref, opcode != opc_invokespecial, cls, args);
} catch (InterpreterException ex) {
constant = false;
Obfuscator.err.println("Can't interpret "+ref+": "
+ ex.getMessage());
/* result is not constant */
} catch (InvocationTargetException ex) {
constant = false;
Obfuscator.err.println("Method "+ref+" throwed exception: "
+ ex.getTargetException().getMessage());
/* method always throws exception ? */
} catch (Exception ex) {
Obfuscator.err.println("Unexpected exception in method: "+ref+" while analyzing "+m);
ex.printStackTrace(Obfuscator.err);
}
}
ConstantAnalyzerValue returnVal;
if (!constant) {
handleReference(ref, opcode == opc_invokevirtual
|| opcode == opc_invokeinterface);
returnVal =
unknownValue[mt.getReturnType().stackSize()-1]; unknownValue[mt.getReturnType().stackSize()-1];
newInfo = info.poppush(size, returnVal); } else {
} else shortInfo.flags |= CONSTANT;
newInfo = info.pop(size); shortInfo.constant = methodResult;
mergeInfo(instr.nextByAddr, newInfo); returnVal = new ConstantAnalyzerValue(methodResult);
returnVal.addConstantListener(shortInfo);
if (clsValue != null)
clsValue.addConstantListener(returnVal);
for (int i=0; i< argValues.length; i++)
argValues[i].addConstantListener(returnVal);
}
mergeInfo(instr.nextByAddr, info.poppush(size, returnVal));
break; break;
} }
@ -1046,15 +1106,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
bytecode.getFirstInstr().tmpInfo = new ConstantAnalyzerInfo bytecode.getFirstInstr().tmpInfo = new ConstantAnalyzerInfo
(bytecode.getMaxLocals(), m.info.isStatic(), m.info.getType()); (bytecode.getMaxLocals(), m.info.isStatic(), m.info.getType());
instrStack.push(bytecode.getFirstInstr()); instrStack.push(bytecode.getFirstInstr());
try { while (!instrStack.isEmpty()) {
while (!instrStack.isEmpty()) { Instruction instr = (Instruction) instrStack.pop();
Instruction instr = (Instruction) instrStack.pop(); handleOpcode(instr);
// System.err.println("addr: "+m+","+instr.addr+";"+instr.tmpInfo);
handleOpcode(instr);
}
} catch (OutOfMemoryError err) {
System.err.println("Out of memory");
System.exit(0);
} }
Handler[] handlers = bytecode.getExceptionHandlers(); Handler[] handlers = bytecode.getExceptionHandlers();
@ -1151,21 +1205,35 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
insertOnePop(instr, 1); insertOnePop(instr, 1);
} else } else
insertOnePop(instr, (instr.opcode == opc_putfield) ? 2 : 1); insertOnePop(instr, (instr.opcode == opc_putfield) ? 2 : 1);
break;
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
case opc_invokevirtual: {
Reference ref = (Reference) instr.objData;
MethodType mt = (MethodType) Type.tType(ref.getType());
for (int i=mt.getParameterTypes().length-1; i >=0; i--)
insertOnePop(instr, mt.getParameterTypes()[i].stackSize());
if (instr.opcode != opc_invokestatic)
insertOnePop(instr, 1);
}
} }
} }
public void appendJump(Instruction instr, Instruction dest) { public void appendJump(Instruction instr, Instruction dest) {
/* Add a goto instruction after this opcode. */ /* Add a goto instruction after this opcode. */
Instruction second = instr.appendInstruction(true); Instruction second = instr.appendInstruction();
second.alwaysJumps = true;
second.opcode = Instruction.opc_goto; second.opcode = Instruction.opc_goto;
second.length = 3; second.length = 3;
second.succs = new Instruction[] { dest }; second.succs = new Instruction[] { dest };
dest.preds.addElement(second); dest.addPredecessor(second);
} }
public BytecodeInfo stripCode() { public BytecodeInfo stripCode() {
if (constInfos == null) if (constInfos == null)
analyzeCode(); analyzeCode();
// bytecode.dumpCode(Obfuscator.err);
for (Instruction instr = bytecode.getFirstInstr(); for (Instruction instr = bytecode.getFirstInstr();
instr != null; instr = instr.nextByAddr) { instr != null; instr = instr.nextByAddr) {
ConstantInfo info = (ConstantInfo) constInfos.get(instr); ConstantInfo info = (ConstantInfo) constInfos.get(instr);
@ -1181,9 +1249,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
instr.localSlot = -1; instr.localSlot = -1;
instr.length = 2; instr.length = 2;
instr.objData = info.constant; instr.objData = info.constant;
// System.err.println(m+": Replacing " // Obfuscator.err.println(m+": Replacing "
// +opcodeString[instr.opcode] // +opcodeString[instr.opcode]
// +" with constant "+info.constant); // +" with constant "+info.constant);
} }
instr.tmpInfo = null; instr.tmpInfo = null;
} else if ((info.flags & CONSTANTFLOW) != 0) { } else if ((info.flags & CONSTANTFLOW) != 0) {
@ -1194,7 +1262,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
else else
instr.opcode = opc_pop; instr.opcode = opc_pop;
instr.alwaysJumps = false; instr.alwaysJumps = false;
instr.succs[0].preds.removeElement(instr); instr.succs[0].removePredecessor(instr);
instr.succs = null; instr.succs = null;
instr.length = 1; instr.length = 1;
while (instr.nextByAddr != null) { while (instr.nextByAddr != null) {

Loading…
Cancel
Save