|
|
|
@ -98,10 +98,15 @@ class ConstantAnalyzerValue implements ConstantListener { |
|
|
|
|
* @return true, if the value changed. |
|
|
|
|
*/ |
|
|
|
|
public void merge(ConstantAnalyzerValue other) { |
|
|
|
|
if (value == other.value) |
|
|
|
|
if (this == other |
|
|
|
|
|| (value == VOLATILE && other.value == VOLATILE)) |
|
|
|
|
return; |
|
|
|
|
if (value != null && value.equals(other.value)) |
|
|
|
|
|
|
|
|
|
if (value == other.value |
|
|
|
|
|| (value != null && value.equals(other.value))) { |
|
|
|
|
other.addConstantListener(this); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (value != VOLATILE) |
|
|
|
|
fireChanged(); |
|
|
|
@ -110,7 +115,6 @@ class ConstantAnalyzerValue implements ConstantListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Analyze the code, assuming every field that is not yet written to |
|
|
|
|
* is constant. This may imply that some code is dead code. |
|
|
|
@ -230,10 +234,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
if (!instrStack.contains(instr)) |
|
|
|
|
instrStack.push(instr); |
|
|
|
|
locals[i] = null; |
|
|
|
|
} else |
|
|
|
|
} else { |
|
|
|
|
locals[i].merge(other.locals[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (stack.length != other.stack.length) |
|
|
|
|
throw new jode.AssertError("stack length differs"); |
|
|
|
|
for (int i=0; i < stack.length; i++) { |
|
|
|
@ -280,25 +285,24 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void handleReference(Reference ref, boolean isVirtual) { |
|
|
|
|
String clName = ref.getClazz(); |
|
|
|
|
/* Don't have to reach array methods */ |
|
|
|
|
if (clName.charAt(0) != '[') { |
|
|
|
|
clName = clName.substring(1, clName.length()-1).replace('/', '.'); |
|
|
|
|
m.clazz.bundle.reachableIdentifier |
|
|
|
|
(ref.getClazz()+"."+ref.getName()+"."+ref.getType(), isVirtual); |
|
|
|
|
(clName+"."+ref.getName()+"."+ref.getType(), isVirtual); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void handleClass(String clName) { |
|
|
|
|
if (clName.charAt(0) == '[') { |
|
|
|
|
int i; |
|
|
|
|
for (i=0; i< clName.length(); i++) |
|
|
|
|
if (clName.charAt(i) != '[') |
|
|
|
|
break; |
|
|
|
|
if (i >= clName.length() || clName.charAt(i) != 'L') |
|
|
|
|
return; |
|
|
|
|
int index = clName.indexOf(';', i); |
|
|
|
|
if (index != clName.length()-1) |
|
|
|
|
return; |
|
|
|
|
clName = clName.substring(i+1, index); |
|
|
|
|
} |
|
|
|
|
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); |
|
|
|
|
m.clazz.bundle.reachableIdentifier(clName, false); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void handleOpcode(Instruction instr) { |
|
|
|
|
ConstantAnalyzerInfo info = (ConstantAnalyzerInfo) instr.tmpInfo; |
|
|
|
@ -926,16 +930,12 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
case opc_putfield: { |
|
|
|
|
int size = (opcode == opc_putstatic) ? 0 : 1; |
|
|
|
|
Reference ref = (Reference) instr.objData; |
|
|
|
|
ClassIdentifier ci = (ClassIdentifier) |
|
|
|
|
m.clazz.bundle.getIdentifier(ref.getClazz()); |
|
|
|
|
if (ci != null) { |
|
|
|
|
FieldIdentifier fi = (FieldIdentifier) |
|
|
|
|
ci.getIdentifier(ref.getName(), ref.getType()); |
|
|
|
|
if (!fi.isNotConstant()) { |
|
|
|
|
m.clazz.bundle.getIdentifier(ref); |
|
|
|
|
if (fi != null && !fi.isNotConstant()) { |
|
|
|
|
fi.setNotConstant(); |
|
|
|
|
fieldNotConstant(fi); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Type type = Type.tType(ref.getType()); |
|
|
|
|
mergeInfo(instr.nextByAddr, info.pop(size + type.stackSize())); |
|
|
|
|
break; |
|
|
|
@ -945,12 +945,13 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
int size = (opcode == opc_getstatic) ? 0 : 1; |
|
|
|
|
Reference ref = (Reference) instr.objData; |
|
|
|
|
Type type = Type.tType(ref.getType()); |
|
|
|
|
ClassIdentifier ci = (ClassIdentifier) |
|
|
|
|
m.clazz.bundle.getIdentifier(ref.getClazz()); |
|
|
|
|
if (ci != null) { |
|
|
|
|
FieldIdentifier fi = (FieldIdentifier) |
|
|
|
|
ci.getIdentifier(ref.getName(), ref.getType()); |
|
|
|
|
if (!fi.isNotConstant()) { |
|
|
|
|
m.clazz.bundle.getIdentifier(ref); |
|
|
|
|
if (fi != null) { |
|
|
|
|
if (fi.isNotConstant()) { |
|
|
|
|
fi.setReachable(); |
|
|
|
|
result = unknownValue[type.stackSize()-1]; |
|
|
|
|
} else { |
|
|
|
|
Object obj = fi.getConstant(); |
|
|
|
|
if (obj == null) |
|
|
|
|
obj = type.getDefaultValue(); |
|
|
|
@ -959,9 +960,6 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
result = new ConstantAnalyzerValue(obj); |
|
|
|
|
result.addConstantListener(shortInfo); |
|
|
|
|
fi.addFieldListener(m); |
|
|
|
|
} else { |
|
|
|
|
fi.setReachable(); |
|
|
|
|
result = unknownValue[type.stackSize()-1]; |
|
|
|
|
} |
|
|
|
|
} else |
|
|
|
|
result = unknownValue[type.stackSize()-1]; |
|
|
|
@ -1012,17 +1010,18 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
(ref, opcode != opc_invokespecial, cls, args); |
|
|
|
|
} catch (InterpreterException ex) { |
|
|
|
|
constant = false; |
|
|
|
|
if (jode.Obfuscator.verboseLevel > 3) |
|
|
|
|
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()); |
|
|
|
|
if (jode.Obfuscator.verboseLevel > 3) |
|
|
|
|
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; |
|
|
|
@ -1050,15 +1049,6 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
mergeInfo(instr.nextByAddr, info.poppush(0, unknownValue[0])); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case opc_newarray: { |
|
|
|
|
mergeInfo(instr.nextByAddr, info.poppush(1, unknownValue[0])); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case opc_anewarray: { |
|
|
|
|
handleClass((String) instr.objData); |
|
|
|
|
mergeInfo(instr.nextByAddr, info.poppush(1, unknownValue[0])); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case opc_arraylength: { |
|
|
|
|
ConstantAnalyzerValue array = info.getStack(1); |
|
|
|
|
if (array.value != ConstantAnalyzerValue.VOLATILE |
|
|
|
@ -1249,9 +1239,10 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
instr.localSlot = -1; |
|
|
|
|
instr.length = 2; |
|
|
|
|
instr.objData = info.constant; |
|
|
|
|
// Obfuscator.err.println(m+": Replacing "
|
|
|
|
|
// +opcodeString[instr.opcode]
|
|
|
|
|
// +" with constant "+info.constant);
|
|
|
|
|
if (Obfuscator.verboseLevel > 2) |
|
|
|
|
Obfuscator.err.println |
|
|
|
|
(m + ": Replacing " + instr |
|
|
|
|
+ " with constant " + info.constant); |
|
|
|
|
} |
|
|
|
|
instr.tmpInfo = null; |
|
|
|
|
} else if ((info.flags & CONSTANTFLOW) != 0) { |
|
|
|
@ -1312,16 +1303,13 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { |
|
|
|
|
case opc_putstatic: |
|
|
|
|
case opc_putfield: { |
|
|
|
|
Reference ref = (Reference) instr.objData; |
|
|
|
|
ClassIdentifier ci = (ClassIdentifier) |
|
|
|
|
m.clazz.bundle.getIdentifier(ref.getClazz()); |
|
|
|
|
if (ci != null) { |
|
|
|
|
FieldIdentifier fi = (FieldIdentifier) |
|
|
|
|
ci.getIdentifier(ref.getName(), ref.getType()); |
|
|
|
|
if (jode.Obfuscator.shouldStrip && !fi.isReachable()) { |
|
|
|
|
m.clazz.bundle.getIdentifier(ref); |
|
|
|
|
if (fi != null |
|
|
|
|
&& jode.Obfuscator.shouldStrip && !fi.isReachable()) { |
|
|
|
|
insertPop(instr); |
|
|
|
|
instr.removeInstruction(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|