JSR handling reworked

Allow fields to get their constant twice.


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1133 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 26 years ago
parent e88bfb332d
commit c41a61b4a3
  1. 419
      jode/jode/obfuscator/ConstantAnalyzer.java.in

@ -45,7 +45,6 @@ import @COLLECTIONS@.ListIterator;
* @author Jochen Hoenicke * @author Jochen Hoenicke
*/ */
public class ConstantAnalyzer implements Opcodes, CodeAnalyzer { public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
Map constInfos;
BytecodeInfo bytecode; BytecodeInfo bytecode;
@ -65,18 +64,25 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
private final static int CMP_EQUAL_MASK private final static int CMP_EQUAL_MASK
= (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ); = (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ);
final static int REACHABLE = 0x1; final static int CONSTANT = 0x02;
final static int CONSTANT = 0x2; final static int CONSTANTFLOW = 0x04;
final static int CONSTANTFLOW = 0x4; final static int RETASTORE = 0x08;
final static int RETURNINGJSR = 0x10;
private interface ConstantListener { private interface ConstantListener {
public void constantChanged(); public void constantChanged();
} }
private static class JSRTargetInfo implements Cloneable { private final static class JSRTargetInfo implements Cloneable {
Instruction jsrTarget; Instruction jsrTarget;
BitSet usedLocals; BitSet usedLocals;
StackLocalInfo retInfo = null;
/**
* The dependent entries, that want to know if the bit set changed.
* This is either a StackLocalInfo (the ret info) or a single
* JSRTargetInfo or a Collection of JSRTargetInfos.
*/
Object dependent;
public JSRTargetInfo(Instruction target) { public JSRTargetInfo(Instruction target) {
jsrTarget = target; jsrTarget = target;
@ -87,28 +93,65 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
try { try {
JSRTargetInfo result = (JSRTargetInfo) clone(); JSRTargetInfo result = (JSRTargetInfo) clone();
result.usedLocals = (BitSet) usedLocals.clone(); result.usedLocals = (BitSet) usedLocals.clone();
addDependent(result);
return result; return result;
} catch (CloneNotSupportedException ex) { } catch (CloneNotSupportedException ex) {
throw new IncompatibleClassChangeError(ex.getMessage()); throw new IncompatibleClassChangeError(ex.getMessage());
} }
} }
private void addDependent(JSRTargetInfo result) {
if (dependent == null || dependent == result)
dependent = result;
else if (dependent instanceof JSRTargetInfo) {
Set newDeps = new HashSet();
newDeps.add(dependent);
newDeps.add(result);
} else if (dependent instanceof Collection) {
((Collection) dependent).add(result);
}
}
public void setRetInfo(StackLocalInfo retInfo) {
dependent = retInfo;
}
public boolean uses(int localSlot) {
return usedLocals.get(localSlot);
}
public void addUsed(int localSlot) {
if (usedLocals.get(localSlot))
return;
usedLocals.set(localSlot);
if (dependent instanceof StackLocalInfo)
((StackLocalInfo) dependent).enqueue();
else if (dependent instanceof JSRTargetInfo)
((JSRTargetInfo) dependent).addUsed(localSlot);
else if (dependent instanceof Collection) {
Iterator iter = ((Collection) dependent).iterator();
while (iter.hasNext()) {
JSRTargetInfo dep = (JSRTargetInfo) iter.next();
dep.addUsed(localSlot);
}
}
}
public void merge(JSRTargetInfo o) { public void merge(JSRTargetInfo o) {
BitSet used = (BitSet) usedLocals.clone(); o.addDependent(this);
used.or(o.usedLocals); for (int slot = 0; slot < o.usedLocals.size(); slot++) {
if (retInfo != null) { if (o.usedLocals.get(slot))
if (o.retInfo != null && o.retInfo != retInfo) addUsed(slot);
throw new AssertError("retInfos differ");
o.retInfo = retInfo;
retInfo.enqueue();
} }
} }
public String toString() { public String toString() {
StringBuffer sb = new StringBuffer(String.valueOf(jsrTarget)); StringBuffer sb = new StringBuffer(String.valueOf(jsrTarget));
if (retInfo != null) if (dependent instanceof StackLocalInfo)
sb.append("->").append(retInfo.instr); sb.append("->").append(((StackLocalInfo) dependent).instr);
return sb.append(usedLocals).toString(); return sb.append(usedLocals)
.append('_').append(hashCode()).toString();
} }
} }
@ -180,8 +223,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
if (this == other) if (this == other)
return; return;
if (value == other.value if (value == null ? other.value == null
|| (value != null && value.equals(other.value))) { : value.equals(other.value)) {
if (value != VOLATILE) { if (value != VOLATILE) {
// other.addConstantListener(this); // other.addConstantListener(this);
this.addConstantListener(other); this.addConstantListener(other);
@ -190,7 +233,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
if (value instanceof JSRTargetInfo if (value instanceof JSRTargetInfo
&& other.value instanceof JSRTargetInfo) { && other.value instanceof JSRTargetInfo
&& (((JSRTargetInfo) value).jsrTarget
== ((JSRTargetInfo) other.value).jsrTarget)) {
((JSRTargetInfo) value).merge((JSRTargetInfo) other.value); ((JSRTargetInfo) value).merge((JSRTargetInfo) other.value);
return; return;
} }
@ -214,6 +259,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
ConstValue[] stack; ConstValue[] stack;
ConstValue[] locals; ConstValue[] locals;
Instruction instr; Instruction instr;
ConstantInfo constInfo;
StackLocalInfo retInfo;
StackLocalInfo nextOnQueue; StackLocalInfo nextOnQueue;
@ -333,20 +380,65 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
for (int i=0; i< locals.length; i++) { for (int i=0; i< locals.length; i++) {
if (locals[i] != null if (locals[i] != null
&& locals[i].value instanceof JSRTargetInfo) { && locals[i].value instanceof JSRTargetInfo) {
JSRTargetInfo jsrInfo = (JSRTargetInfo)locals[i].value;
if (!jsrInfo.uses(slot)) {
jsrInfo = jsrInfo.copy();
locals[i] = locals[i].copy(); locals[i] = locals[i].copy();
locals[i].value = ((JSRTargetInfo) locals[i].value).copy(); locals[i].value = jsrInfo;
((JSRTargetInfo)locals[i].value).usedLocals.set(slot); jsrInfo.addUsed(slot);
}
} }
} }
for (int i=0; i< stack.length; i++) { for (int i=0; i< stack.length; i++) {
if (stack[i] != null if (stack[i] != null
&& stack[i].value instanceof JSRTargetInfo) { && stack[i].value instanceof JSRTargetInfo) {
JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value;
if (!jsrInfo.uses(slot)) {
jsrInfo = jsrInfo.copy();
stack[i] = stack[i].copy();
stack[i].value = jsrInfo;
jsrInfo.addUsed(slot);
}
}
}
return this;
}
public StackLocalInfo mergeRetLocals(JSRTargetInfo jsrTargetInfo,
StackLocalInfo retInfo) {
for (int slot = 0; slot < locals.length; slot++) {
if (jsrTargetInfo.uses(slot))
locals[slot] = retInfo.locals[slot];
}
locals[retInfo.instr.getLocalSlot()] = null;
for (int i=0; i< locals.length; i++) {
if (locals[i] != null
&& locals[i].value instanceof JSRTargetInfo) {
JSRTargetInfo jsrInfo = (JSRTargetInfo) locals[i].value;
jsrInfo = jsrInfo.copy();
locals[i] = locals[i].copy(); locals[i] = locals[i].copy();
locals[i].value = ((JSRTargetInfo)locals[i].value).copy(); locals[i].value = jsrInfo;
((JSRTargetInfo)locals[i].value).usedLocals.set(slot); for (int slot = 0; slot < locals.length; slot++) {
if (jsrTargetInfo.uses(slot))
jsrInfo.addUsed(slot);
} }
} }
return new StackLocalInfo(stack, locals, notifyQueue); }
for (int i=0; i< stack.length; i++) {
if (stack[i] != null
&& stack[i].value instanceof JSRTargetInfo) {
JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value;
jsrInfo = jsrInfo.copy();
stack[i] = stack[i].copy();
stack[i].value = jsrInfo;
for (int slot = 0; slot < locals.length; slot++) {
if (jsrTargetInfo.uses(slot))
jsrInfo.addUsed(slot);
}
}
}
return this;
} }
public void merge(StackLocalInfo other) { public void merge(StackLocalInfo other) {
@ -378,7 +470,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
private static class ConstantInfo implements ConstantListener { private static class ConstantInfo implements ConstantListener {
ConstantInfo() { ConstantInfo() {
this(REACHABLE, null); this(0, null);
} }
ConstantInfo(int flags) { ConstantInfo(int flags) {
@ -488,7 +580,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
public void handleOpcode(StackLocalInfo info, Identifier fieldListener) { public void handleOpcode(StackLocalInfo info, Identifier fieldListener) {
Instruction instr = info.instr; Instruction instr = info.instr;
constInfos.put(instr, unknownConstInfo); info.constInfo = unknownConstInfo;
int opcode = instr.getOpcode(); int opcode = instr.getOpcode();
Handler[] handlers = bytecode.getExceptionHandlers(); Handler[] handlers = bytecode.getExceptionHandlers();
@ -519,11 +611,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
System.err.println(instr); System.err.println(instr);
} }
if (result.value != ConstValue.VOLATILE) { if (result.value != ConstValue.VOLATILE) {
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANT, result.value);
constInfos.put(instr, shortInfo); result.addConstantListener(info.constInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = result.value;
result.addConstantListener(shortInfo);
} }
mergeInfo(instr.getNextByAddr(), mergeInfo(instr.getNextByAddr(),
info.poppush(0, result) info.poppush(0, result)
@ -573,8 +662,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
break; break;
} }
case opc_istore: case opc_fstore: case opc_astore: { case opc_istore: case opc_fstore: case opc_astore: {
result = info.getStack(1);
if (result.value instanceof JSRTargetInfo)
info.constInfo.flags |= RETASTORE;
mergeInfo(instr.getNextByAddr(), mergeInfo(instr.getNextByAddr(),
info.pop(1).setLocal(instr.getLocalSlot(), info.getStack(1))); info.pop(1).setLocal(instr.getLocalSlot(), result));
break; break;
} }
case opc_lstore: case opc_dstore: { case opc_lstore: case opc_dstore: {
@ -590,8 +682,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
mergeInfo(instr.getNextByAddr(), info.pop(2+size)); mergeInfo(instr.getNextByAddr(), info.pop(2+size));
break; break;
} }
case opc_pop: case opc_pop2: case opc_pop:
mergeInfo(instr.getNextByAddr(), info.pop(opcode - (opc_pop - 1))); mergeInfo(instr.getNextByAddr(), info.pop(1));
break;
case opc_pop2:
mergeInfo(instr.getNextByAddr(), info.pop(2));
break; break;
case opc_dup: case opc_dup_x1: case opc_dup_x2: case opc_dup: case opc_dup_x1: case opc_dup_x2:
@ -763,12 +858,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
default: default:
throw new jode.AssertError("Can't happen."); throw new jode.AssertError("Can't happen.");
} }
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANT, newValue);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = newValue;
result = new ConstValue(newValue); result = new ConstValue(newValue);
result.addConstantListener(shortInfo); result.addConstantListener(info.constInfo);
value1.addConstantListener(result); value1.addConstantListener(result);
value2.addConstantListener(result); value2.addConstantListener(result);
} else } else
@ -801,12 +893,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
default: default:
throw new jode.AssertError("Can't happen."); throw new jode.AssertError("Can't happen.");
} }
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANT, newValue);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = newValue;
result = new ConstValue(newValue); result = new ConstValue(newValue);
result.addConstantListener(shortInfo); result.addConstantListener(info.constInfo);
value.addConstantListener(result); value.addConstantListener(result);
} else } else
result = unknownValue[size-1]; result = unknownValue[size-1];
@ -857,12 +946,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
default: default:
throw new jode.AssertError("Can't happen."); throw new jode.AssertError("Can't happen.");
} }
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANT, newValue);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = newValue;
result = new ConstValue(newValue); result = new ConstValue(newValue);
result.addConstantListener(shortInfo); result.addConstantListener(info.constInfo);
value1.addConstantListener(result); value1.addConstantListener(result);
value2.addConstantListener(result); value2.addConstantListener(result);
} else } else
@ -907,12 +993,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
default: default:
throw new jode.AssertError("Can't happen."); throw new jode.AssertError("Can't happen.");
} }
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANT, newVal);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = newVal;
result = new ConstValue(newVal); result = new ConstValue(newVal);
result.addConstantListener(shortInfo); result.addConstantListener(info.constInfo);
stack.addConstantListener(result); stack.addConstantListener(result);
} else { } else {
switch (opcode) { switch (opcode) {
@ -942,12 +1025,10 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
val = (short) val; val = (short) val;
break; break;
} }
ConstantInfo shortInfo = new ConstantInfo(); Integer newVal = new Integer(val);
constInfos.put(instr, shortInfo); info.constInfo = new ConstantInfo(CONSTANT, newVal);
shortInfo.flags |= CONSTANT; result = new ConstValue(newVal);
shortInfo.constant = new Integer(val); stack.addConstantListener(info.constInfo);
result = new ConstValue(shortInfo.constant);
stack.addConstantListener(shortInfo);
stack.addConstantListener(result); stack.addConstantListener(result);
} else } else
result = unknownValue[0]; result = unknownValue[0];
@ -962,13 +1043,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
&& val2.value != ConstValue.VOLATILE) { && val2.value != ConstValue.VOLATILE) {
long value1 = ((Long) val1.value).longValue(); long value1 = ((Long) val1.value).longValue();
long value2 = ((Long) val1.value).longValue(); long value2 = ((Long) val1.value).longValue();
ConstantInfo shortInfo = new ConstantInfo(); Integer newVal = new Integer(value1 == value2 ? 0
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = new Integer(value1 == value2 ? 0
: value1 < value2 ? -1 : 1); : value1 < value2 ? -1 : 1);
result = new ConstValue(shortInfo.constant); info.constInfo = new ConstantInfo(CONSTANT, newVal);
result.addConstantListener(shortInfo); result = new ConstValue(newVal);
result.addConstantListener(info.constInfo);
val1.addConstantListener(result); val1.addConstantListener(result);
val2.addConstantListener(result); val2.addConstantListener(result);
} else } else
@ -983,16 +1062,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
&& val2.value != ConstValue.VOLATILE) { && val2.value != ConstValue.VOLATILE) {
float value1 = ((Float) val1.value).floatValue(); float value1 = ((Float) val1.value).floatValue();
float value2 = ((Float) val1.value).floatValue(); float value2 = ((Float) val1.value).floatValue();
ConstantInfo shortInfo = new ConstantInfo(); Integer newVal = new Integer
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = new Integer
(value1 == value2 ? 0 (value1 == value2 ? 0
: ( opcode == opc_fcmpg : ( opcode == opc_fcmpg
? (value1 < value2 ? -1 : 1) ? (value1 < value2 ? -1 : 1)
: (value1 > value2 ? 1 : -1))); : (value1 > value2 ? 1 : -1)));
result = new ConstValue(shortInfo.constant); info.constInfo = new ConstantInfo(CONSTANT, newVal);
result.addConstantListener(shortInfo); result = new ConstValue(newVal);
result.addConstantListener(info.constInfo);
val1.addConstantListener(result); val1.addConstantListener(result);
val2.addConstantListener(result); val2.addConstantListener(result);
} else } else
@ -1007,16 +1084,14 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
&& val2.value != ConstValue.VOLATILE) { && val2.value != ConstValue.VOLATILE) {
double value1 = ((Double) val1.value).doubleValue(); double value1 = ((Double) val1.value).doubleValue();
double value2 = ((Double) val1.value).doubleValue(); double value2 = ((Double) val1.value).doubleValue();
ConstantInfo shortInfo = new ConstantInfo(); Integer newVal = new Integer
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = new Integer
(value1 == value2 ? 0 (value1 == value2 ? 0
: ( opcode == opc_dcmpg : ( opcode == opc_dcmpg
? (value1 < value2 ? -1 : 1) ? (value1 < value2 ? -1 : 1)
: (value1 > value2 ? 1 : -1))); : (value1 > value2 ? 1 : -1)));
result = new ConstValue(shortInfo.constant); info.constInfo = new ConstantInfo(CONSTANT, newVal);
result.addConstantListener(shortInfo); result = new ConstValue(newVal);
result.addConstantListener(info.constInfo);
val1.addConstantListener(result); val1.addConstantListener(result);
val2.addConstantListener(result); val2.addConstantListener(result);
} else } else
@ -1077,10 +1152,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
if ((opc_mask & (1<<opcode)) != 0) if ((opc_mask & (1<<opcode)) != 0)
pc = instr.getSingleSucc(); pc = instr.getSingleSucc();
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANTFLOW, pc);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANTFLOW;
shortInfo.constant = pc;
mergeInfo(pc, info.pop(size)); mergeInfo(pc, info.pop(size));
} else { } else {
mergeInfo(instr.getNextByAddr(), info.pop(size)); mergeInfo(instr.getNextByAddr(), info.pop(size));
@ -1091,12 +1163,6 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_goto: case opc_goto:
mergeInfo(instr.getSingleSucc(), info.copy()); mergeInfo(instr.getSingleSucc(), info.copy());
break; break;
case opc_jsr:
mergeInfo(instr.getSingleSucc(),
info.poppush(0, new ConstValue
(new JSRTargetInfo(instr.getSingleSucc()))
));
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) {
@ -1111,10 +1177,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
break; break;
} }
} }
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANTFLOW, pc);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANTFLOW;
shortInfo.constant = pc;
mergeInfo(pc, info.pop(1)); mergeInfo(pc, info.pop(1));
} else { } else {
for (int i=0; i < instr.getSuccs().length; i++) for (int i=0; i < instr.getSuccs().length; i++)
@ -1122,28 +1185,48 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
} }
break; break;
} }
case opc_jsr:
// dumpStackLocalInfo();
// System.err.println(instr);
if (instr.getSingleSucc().getOpcode() != opc_astore)
throw new RuntimeException("Can't handle jsr to non astores");
StackLocalInfo oldJsrInfo =
(StackLocalInfo) instr.getSingleSucc().getTmpInfo();
if (oldJsrInfo != null) {
result = oldJsrInfo.getStack(1);
if (oldJsrInfo.retInfo != null
&& result.value instanceof JSRTargetInfo) {
mergeInfo(instr.getNextByAddr(),
info.copy()
.mergeRetLocals((JSRTargetInfo) result.value,
oldJsrInfo.retInfo));
}
} else {
result = new ConstValue
(new JSRTargetInfo(instr.getSingleSucc()));
}
mergeInfo(instr.getSingleSucc(), info.poppush(0, result));
break;
case opc_ret: { case opc_ret: {
// dumpStackLocalInfo(); // dumpStackLocalInfo();
// System.err.println(instr); // System.err.println(instr);
result = info.getLocal(instr.getLocalSlot()); result = info.getLocal(instr.getLocalSlot());
JSRTargetInfo jsrInfo = (JSRTargetInfo) result.value; JSRTargetInfo jsrInfo = (JSRTargetInfo) result.value;
jsrInfo.retInfo = info; jsrInfo.setRetInfo(info);
result.addConstantListener(info); result.addConstantListener(info);
Instruction jsrTarget = jsrInfo.jsrTarget; Instruction jsrTarget = jsrInfo.jsrTarget;
for (int i=0; i < jsrTarget.getPreds().length; i++) { StackLocalInfo jsrTargetStackInfo =
Instruction jsr = jsrTarget.getPreds()[i]; (StackLocalInfo) jsrTarget.getTmpInfo();
if (jsr.getTmpInfo() == null) jsrTargetStackInfo.retInfo = info;
continue; jsrTargetStackInfo.constInfo.flags |= RETURNINGJSR;
StackLocalInfo nextInfo Instruction[] jsrs = jsrTarget.getPreds();
= ((StackLocalInfo) jsr.getTmpInfo()).copy(); for (int i=0; i < jsrs.length; i++) {
int maxLocals = bytecode.getMaxLocals(); Instruction jsr = jsrs[i];
for (int slot = 0; slot < maxLocals; slot++) { if (jsr.getTmpInfo() != null) {
if (slot == instr.getLocalSlot()) mergeInfo(jsr.getNextByAddr(),
nextInfo.setLocal(slot, null); ((StackLocalInfo) jsr.getTmpInfo()).copy()
else if (jsrInfo.usedLocals.get(slot)) .mergeRetLocals(jsrInfo, info));
nextInfo.setLocal(slot, info.getLocal(slot));
} }
mergeInfo(jsr.getNextByAddr(), nextInfo);
} }
break; break;
} }
@ -1156,13 +1239,22 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
case opc_putstatic: case opc_putstatic:
case opc_putfield: { case opc_putfield: {
FieldIdentifier fi = (FieldIdentifier) canonizeReference(instr); FieldIdentifier fi = (FieldIdentifier) canonizeReference(instr);
int size = (opcode == opc_putstatic) ? 0 : 1;
Reference ref = instr.getReference(); Reference ref = instr.getReference();
size += TypeSignature.getTypeSize(ref.getType()); int size = TypeSignature.getTypeSize(ref.getType());
if (fi != null && !fi.isNotConstant()) { if (fi != null && !fi.isNotConstant()) {
ConstValue stacktop = info.getStack(size);
Object fieldVal = fi.getConstant();
if (fieldVal == null)
fieldVal = runtime.getDefaultValue(ref.getType());
if (stacktop.value == null ? fieldVal == null
: stacktop.value.equals(fieldVal)) {
stacktop.addConstantListener(info);
} else {
fi.setNotConstant(); fi.setNotConstant();
fieldNotConstant(fi); fieldNotConstant(fi);
} }
}
size += (opcode == opc_putstatic) ? 0 : 1;
mergeInfo(instr.getNextByAddr(), info.pop(size)); mergeInfo(instr.getNextByAddr(), info.pop(size));
break; break;
} }
@ -1178,32 +1270,11 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
result = unknownValue[typesize - 1]; result = unknownValue[typesize - 1];
} else { } else {
Object obj = fi.getConstant(); Object obj = fi.getConstant();
if (obj == null) { if (obj == null)
switch (ref.getType().charAt(0)) { obj = runtime.getDefaultValue(ref.getType());
case 'Z': info.constInfo = new ConstantInfo(CONSTANT, obj);
case 'B':
case 'S':
case 'C':
case 'I':
obj = new Integer(0);
break;
case 'J':
obj = new Long(0);
break;
case 'F':
obj = new Float(0);
break;
case 'D':
obj = new Double(0);
break;
}
}
ConstantInfo shortInfo = new ConstantInfo();
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = obj;
result = new ConstValue(obj); result = new ConstValue(obj);
result.addConstantListener(shortInfo); result.addConstantListener(info.constInfo);
fi.addFieldListener(fieldListener); fi.addFieldListener(fieldListener);
} }
} else } else
@ -1280,12 +1351,9 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
int retsize = TypeSignature.getTypeSize(retType); int retsize = TypeSignature.getTypeSize(retType);
returnVal = unknownValue[retsize - 1]; returnVal = unknownValue[retsize - 1];
} else { } else {
ConstantInfo shortInfo = new ConstantInfo(); info.constInfo = new ConstantInfo(CONSTANT, methodResult);
constInfos.put(instr, shortInfo);
shortInfo.flags |= CONSTANT;
shortInfo.constant = methodResult;
returnVal = new ConstValue(methodResult); returnVal = new ConstValue(methodResult);
returnVal.addConstantListener(shortInfo); returnVal.addConstantListener(info.constInfo);
if (clsValue != null) if (clsValue != null)
clsValue.addConstantListener(returnVal); clsValue.addConstantListener(returnVal);
for (int i=0; i< argValues.length; i++) for (int i=0; i< argValues.length; i++)
@ -1304,10 +1372,10 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
// ConstValue array = info.getStack(1); // ConstValue array = info.getStack(1);
// if (array.value != ConstValue.VOLATILE // if (array.value != ConstValue.VOLATILE
// && array.value != null) { // && array.value != null) {
// shortInfo.flags |= CONSTANT; // Integer newValue = new Integer(Array.getLength(array.value));
// shortInfo.constant = new Integer(Array.getLength(array.value)); // info.constInfo = new ConstantInfo(CONSTANT, newValue);
// result = new ConstValue(shortInfo.constant); // result = new ConstValue(newValue);
// result.addConstantListener(shortInfo); // result.addConstantListener(info.constInfo);
// array.addConstantListener(result); // array.addConstantListener(result);
// } else // } else
result = unknownValue[0]; result = unknownValue[0];
@ -1334,9 +1402,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
info.poppush(instr.getDimensions(), unknownValue[0])); info.poppush(instr.getDimensions(), unknownValue[0]));
break; break;
default: default:
throw new jode.AssertError("Invalid opcode "+opcode); throw new IllegalArgumentException("Invalid opcode "+opcode);
} }
} }
public void fieldNotConstant(FieldIdentifier fi) { public void fieldNotConstant(FieldIdentifier fi) {
@ -1359,8 +1426,7 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
for (Iterator iter = bytecode.getInstructions().iterator(); for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next(); Instruction instr = (Instruction) iter.next();
StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo(); System.err.println(""+instr.getTmpInfo());
System.err.println(""+info);
System.err.println(instr.getDescription()); System.err.println(instr.getDescription());
} }
} }
@ -1368,10 +1434,15 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
public void analyzeCode(MethodIdentifier methodIdent, public void analyzeCode(MethodIdentifier methodIdent,
BytecodeInfo bytecode) { BytecodeInfo bytecode) {
this.bytecode = bytecode; this.bytecode = bytecode;
if (constInfos == null)
constInfos = new HashMap();
TodoQueue modifiedQueue = new TodoQueue(); TodoQueue modifiedQueue = new TodoQueue();
MethodInfo minfo = bytecode.getMethodInfo(); MethodInfo minfo = bytecode.getMethodInfo();
for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next();
instr.setTmpInfo(null);
}
StackLocalInfo firstInfo = new StackLocalInfo StackLocalInfo firstInfo = new StackLocalInfo
(bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(), (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(),
modifiedQueue); modifiedQueue);
@ -1392,8 +1463,16 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
Main.getClassBundle().reachableClass(handlers[i].type); Main.getClassBundle().reachableClass(handlers[i].type);
} }
for (Iterator iter = bytecode.getInstructions().iterator(); for (Iterator iter = bytecode.getInstructions().iterator();
iter.hasNext(); ) iter.hasNext(); ) {
((Instruction) iter.next()).setTmpInfo(null); Instruction instr = (Instruction) iter.next();
StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo();
if (info != null) {
if (info.constInfo.flags == 0)
instr.setTmpInfo(unknownConstInfo);
else
instr.setTmpInfo(info.constInfo);
}
}
} }
public static void replaceWith(ListIterator iter, Instruction instr, public static void replaceWith(ListIterator iter, Instruction instr,
@ -1509,9 +1588,13 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
for (ListIterator iter = bytecode.getInstructions().listIterator(); for (ListIterator iter = bytecode.getInstructions().listIterator();
iter.hasNext(); ) { iter.hasNext(); ) {
Instruction instr = (Instruction) iter.next(); Instruction instr = (Instruction) iter.next();
ConstantInfo info = (ConstantInfo) constInfos.get(instr); ConstantInfo info = (ConstantInfo) instr.getTmpInfo();
if (info == null || (info.flags & REACHABLE) == 0) { instr.setTmpInfo(null);
/* This instruction can't be reached logically */
if (info == null
|| (info.flags & (RETURNINGJSR | RETASTORE)) == RETASTORE) {
/* This instruction can't be reached logically, or
* it is a return value astore, that should be removed */
iter.remove(); iter.remove();
} else if ((info.flags & CONSTANT) != 0) { } else if ((info.flags & CONSTANT) != 0) {
if (instr.getOpcode() > opc_ldc2_w) { if (instr.getOpcode() > opc_ldc2_w) {
@ -1539,9 +1622,8 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
+ " with goto " + pc.getAddr()); + " with goto " + pc.getAddr());
while (iter.hasNext()) { while (iter.hasNext()) {
ConstantInfo nextinfo = (ConstantInfo) ConstantInfo nextinfo = (ConstantInfo)
constInfos.get((Instruction) iter.next()); ((Instruction) iter.next()).getTmpInfo();
if (nextinfo != null if (nextinfo != null) {
&& (nextinfo.flags & REACHABLE) != 0) {
Instruction nextInstr = (Instruction) iter.previous(); Instruction nextInstr = (Instruction) iter.previous();
if (pc != nextInstr) if (pc != nextInstr)
appendJump(iter, pc); appendJump(iter, pc);
@ -1558,6 +1640,21 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
iter.remove(); iter.remove();
break; break;
case opc_jsr:
ConstantInfo jsrinfo = (ConstantInfo)
instr.getSingleSucc().getTmpInfo();
if ((jsrinfo.flags & RETURNINGJSR) != 0)
/* A normal jsr, don't change it */
break;
/* This means, the jsr will never return. We
* replace it with a goto, the jsr will transform
* itself to remove the astore operation.
*/
Instruction gotoInstr = new Instruction(opc_goto);
gotoInstr.setSuccs(instr.getSingleSucc());
iter.set(gotoInstr);
/* fall through */
case opc_goto: case opc_goto:
case opc_ifeq: case opc_ifne: case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge: case opc_iflt: case opc_ifge:
@ -1570,18 +1667,22 @@ public class ConstantAnalyzer implements Opcodes, CodeAnalyzer {
while (iter.hasNext()) { while (iter.hasNext()) {
ConstantInfo nextinfo = (ConstantInfo) ConstantInfo nextinfo = (ConstantInfo)
constInfos.get((Instruction) iter.next()); ((Instruction) iter.next()).getTmpInfo();
if (nextinfo != null if (nextinfo != null
&& (nextinfo.flags & REACHABLE) != 0) { && ((nextinfo.flags & (RETURNINGJSR | RETASTORE))
!= RETASTORE)) {
Instruction nextInstr Instruction nextInstr
= (Instruction) iter.previous(); = (Instruction) iter.previous();
if (instr.getSingleSucc() == nextInstr) { if (instr.getSingleSucc() == nextInstr) {
/* put iter in sane state */
iter.previous(); iter.previous();
iter.next();
replaceWith(iter, instr, null); replaceWith(iter, instr, null);
} }
break; break;
} }
/* Next instruction can't be reached logically */ /* Next instruction can be removed */
iter.remove(); iter.remove();
} }
break; break;

Loading…
Cancel
Save