bug fixes for jsr handling.

Create updated LocalVariableTable


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@646 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 4155cb3a02
commit 5f12f1e3ea
  1. 502
      jode/jode/obfuscator/LocalOptimizer.java

@ -20,6 +20,7 @@
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.Obfuscator; import jode.Obfuscator;
@ -27,8 +28,34 @@ import jode.Obfuscator;
* 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.
* *
* This class can only work on verified code. There should also be * This class can only work on verified code. There should also be no
* no deadcode, since we can't be sure that deadcode behaves okay. * deadcode, since the verifier doesn't check that deadcode behaves
* okay.
*
* This is done in two phases. First we determine which locals are
* the same, and which locals have a overlapping life time. In the
* second phase we will then redistribute the locals with a coloring
* graph algorithm.
*
* The idea for the first phase is: For each read we follow the
* instruction flow backward to find the corresponding writes. We can
* also merge with another control flow that has a different read, in
* this case we merge with that read, too.
*
* The tricky part is the subroutine handling. We follow the local
* that is used in a ret and find the corresponding jsr target (there
* must be only one, if the verifier should accept this class). While
* we do this we remember in the info of the ret, which locals are
* used in that subroutine.
*
* When we know the jsr target<->ret correlation, we promote from the
* nextByAddr of every jsr the locals that are accessed by the
* subroutine to the corresponding ret and the others to the jsr. Also
* we will promote all reads from the jsr targets to the jsr.
*
* If you think this might be to complicated, keep in mind that jsr's
* are not only left by the ret instructions, but also "spontanously"
* (by not reading the return address again).
*/ */
public class LocalOptimizer implements Opcodes { public class LocalOptimizer implements Opcodes {
@ -53,11 +80,6 @@ public class LocalOptimizer implements Opcodes {
Vector conflictingLocals = new Vector(); Vector conflictingLocals = new Vector();
int size; int size;
int newSlot = -1; int newSlot = -1;
/**
* If this local is used as returnAddress, this gives the
* ret that uses it.
*/
InstrInfo retInfo;
LocalInfo() { LocalInfo() {
} }
@ -91,12 +113,6 @@ public class LocalOptimizer implements Opcodes {
shadow.name = name; shadow.name = name;
shadow.type = type; shadow.type = type;
} }
if (retInfo != null) {
if (retInfo != shadow.retInfo)
Obfuscator.err.println
("Warning: Multiple rets on one jsr?");
shadow.retInfo = retInfo;
}
Enumeration enum = usingInstrs.elements(); Enumeration enum = usingInstrs.elements();
while (enum.hasMoreElements()) { while (enum.hasMoreElements()) {
InstrInfo instr = (InstrInfo) enum.nextElement(); InstrInfo instr = (InstrInfo) enum.nextElement();
@ -117,33 +133,34 @@ public class LocalOptimizer implements Opcodes {
*/ */
LocalInfo local; LocalInfo local;
/** /**
* For each slot, this contains the LocalInfo of the next * For each slot, this contains the InstrInfo of one of the
* Instruction, that may read from that slot, without prior * next Instruction, that may read from that slot, without
* writing. * prior writing. */
InstrInfo[] nextReads;
/**
* This only has a value for ret instructions. In that case
* this bitset contains all locals, that may be used between
* jsr and ret.
*/ */
LocalInfo[] nextReads; BitSet usedBySub;
/** /**
* For each slot if get() is true, no instruction may read * For each slot if get() is true, no instruction may read
* this slot, since it may contain different locals, depending * this slot, since it may contain different locals, depending
* on flow. * on flow.
*/ */
BitSet conflictingLocals; LocalInfo[] lifeLocals;
/** /**
* If instruction is the destination of a jsr, this contains * If instruction is the destination of a jsr, this contains
* the single allowed ret instructions, or null if there is * the single allowed ret instruction info, or null if there
* no ret at all. * is no ret at all (or not yet detected).
*/ */
Instruction retInstr; InstrInfo retInfo;
/**
* If instruction is a jsr, this contains the slots
* used by the sub routine
*/
BitSet usedBySub;
/** /**
* The jsr to which the nextReads at this slot belongs to. * If this instruction is a ret, this contains the single
* I think I don't like jsrs any more. * allowed jsr target to which this ret belongs.
*/ */
Vector[] belongsToJsrs; InstrInfo jsrTargetInfo;
/** /**
* The Instruction of this info * The Instruction of this info
*/ */
@ -154,69 +171,22 @@ public class LocalOptimizer implements Opcodes {
InstrInfo nextInfo; InstrInfo nextInfo;
} }
BytecodeInfo bc;
MethodInfo methodInfo;
InstrInfo firstInfo; InstrInfo firstInfo;
Stack changedInfos; Stack changedInfos;
Hashtable instrInfos; Hashtable instrInfos;
BytecodeInfo bc;
boolean produceLVT; boolean produceLVT;
int maxlocals; int maxlocals;
int paramCount;
public LocalOptimizer(BytecodeInfo bc, int paramCount) { LocalInfo[] paramLocals;
public LocalOptimizer(BytecodeInfo bc, MethodInfo methodInfo) {
this.bc = bc; this.bc = bc;
this.paramCount = paramCount; this.methodInfo = methodInfo;
} }
/**
* This method determines which rets belong to a given jsr. This
* is needed, since the predecessors must be exact.
*/
void analyzeSubRoutine(InstrInfo subInfo) {
Stack instrStack = new Stack();
Instruction subInstr = subInfo.instr;
if (subInfo.usedBySub != null)
return;
subInfo.usedBySub = new BitSet(maxlocals);
if (subInstr.opcode != opc_astore) {
/* Grrr, the bytecode verifier doesn't test if a
* jsr starts with astore. So it is possible to
* do something else before putting the ret address
* into a local. It would be even possible to pop
* the address, and never return.
*/
throw new AssertError("Non standard jsr");
}
int slot = subInstr.localSlot;
subInfo.usedBySub.set(slot);
instrStack.push(subInstr.nextByAddr);
while (!instrStack.isEmpty()) {
Instruction instr = (Instruction) instrStack.pop();
if (instr.localSlot == slot) {
if (instr.opcode >= opc_istore
&& instr.opcode <= opc_astore)
/* Return address is overwritten, we will never
* return.
*/
continue;
if (instr.opcode != opc_ret
|| (subInfo.retInstr != null
&& subInfo.retInstr != instr))
/* This can't happen in legal bytecode. */
throw new AssertError("Illegal bytecode");
subInfo.retInstr = instr;
} else if (instr.localSlot != -1) {
subInfo.usedBySub.set(instr.localSlot);
}
if (!instr.alwaysJumps)
instrStack.push(instr.nextByAddr);
if (instr.succs != null)
for (int i=0; i< instr.succs.length; i++)
instrStack.push(instr.succs[i]);
}
}
/** /**
* Merges the given vector to a new vector. Both vectors may * Merges the given vector to a new vector. Both vectors may
@ -239,36 +209,8 @@ public class LocalOptimizer implements Opcodes {
return result; return result;
} }
void promoteSubRoutineReads(InstrInfo info, Instruction preInstr, void promoteReads(InstrInfo info, Instruction preInstr,
InstrInfo jsrInfo) { BitSet mergeSet, boolean inverted) {
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr);
int omitLocal = -1;
if (preInstr.localSlot != -1
&& preInstr.opcode >= opc_istore
&& preInstr.opcode <= opc_astore) {
/* This is a store */
omitLocal = preInstr.localSlot;
if (info.nextReads[preInstr.localSlot] != null)
preInfo.local.combineInto
(info.nextReads[preInstr.localSlot]);
}
for (int i=0; i < maxlocals; i++) {
if (info.nextReads[i] != null && i != omitLocal
&& (jsrInfo == null || !jsrInfo.usedBySub.get(i))) {
if (preInfo.nextReads[i] == null) {
preInfo.nextReads[i] = info.nextReads[i];
changedInfos.push(preInfo);
} else {
preInfo.nextReads[i]
.combineInto(info.nextReads[i]);
}
}
}
}
void promoteNotModifiedReads(InstrInfo info, Instruction preInstr,
InstrInfo jsrInfo) {
InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr); InstrInfo preInfo = (InstrInfo) instrInfos.get(preInstr);
int omitLocal = -1; int omitLocal = -1;
if (preInstr.localSlot != -1 if (preInstr.localSlot != -1
@ -278,53 +220,98 @@ public class LocalOptimizer implements Opcodes {
omitLocal = preInstr.localSlot; omitLocal = preInstr.localSlot;
if (info.nextReads[preInstr.localSlot] != null) if (info.nextReads[preInstr.localSlot] != null)
preInfo.local.combineInto preInfo.local.combineInto
(info.nextReads[preInstr.localSlot]); (info.nextReads[preInstr.localSlot].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
&& (jsrInfo == null || !jsrInfo.usedBySub.get(i))) { && (mergeSet == null || mergeSet.get(i) != inverted)) {
if (preInfo.nextReads[i] == null) { if (preInfo.nextReads[i] == null) {
preInfo.nextReads[i] = info.nextReads[i]; preInfo.nextReads[i] = info.nextReads[i];
changedInfos.push(preInfo); changedInfos.push(preInfo);
} else { } else {
preInfo.nextReads[i] preInfo.nextReads[i].local
.combineInto(info.nextReads[i]); .combineInto(info.nextReads[i].local);
} }
} }
} }
} }
void promoteReads(InstrInfo info, Instruction preInstr) { void promoteReads(InstrInfo info, Instruction preInstr) {
promoteNotModifiedReads(info, preInstr, null); promoteReads(info, preInstr, null, false);
} }
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt, public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
Instruction instr) { int slot, int addr) {
int addr = instr.addr;
if (instr.opcode >= opc_istore
&& instr.opcode <= opc_astore)
addr += instr.length;
LocalVariableInfo match = null; LocalVariableInfo match = null;
for (int i=0; i < lvt.length; i++) { for (int i=0; i < lvt.length; i++) {
if (lvt[i].slot == instr.localSlot if (lvt[i].slot == slot
&& lvt[i].start.addr <= addr && lvt[i].start.addr <= addr
&& lvt[i].end.addr > addr) { && lvt[i].end.addr >= addr) {
if (match != null) if (match != null
&& (!match.name.equals(lvt[i].name)
|| !match.type.equals(lvt[i].type))) {
/* Multiple matches..., give no info */ /* Multiple matches..., give no info */
return null; return null;
}
match = lvt[i]; match = lvt[i];
} }
} }
return match; return match;
} }
public LocalVariableInfo findLVTEntry(LocalVariableInfo[] lvt,
Instruction instr) {
int addr = instr.addr;
if (instr.opcode >= opc_istore
&& instr.opcode <= opc_astore)
addr += instr.length;
return findLVTEntry(lvt, instr.localSlot, addr);
}
public void calcLocalInfo() { public void calcLocalInfo() {
maxlocals = bc.getMaxLocals(); maxlocals = bc.getMaxLocals();
Handler[] handlers = bc.getExceptionHandlers(); Handler[] handlers = bc.getExceptionHandlers();
LocalVariableInfo[] lvt = bc.getLocalVariableTable(); LocalVariableInfo[] lvt = bc.getLocalVariableTable();
if (lvt != null) if (lvt != null)
produceLVT = true; produceLVT = true;
/* Initialize paramLocals */
{
int paramCount = methodInfo.isStatic() ? 0 : 1;
Type[] paramTypes =
Type.tMethod(methodInfo.getType()).getParameterTypes();
for (int i = paramTypes.length; i-- > 0;)
paramCount += paramTypes[i].stackSize();
paramLocals = new LocalInfo[paramCount];
int slot = 0;
if (!methodInfo.isStatic()) {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, 0, 0);
if (lvi != null) {
local.name = lvi.name;
local.type = lvi.type;
}
}
local.size = 1;
paramLocals[slot++] = local;
}
for (int i = 0; i< paramTypes.length; i++) {
LocalInfo local = new LocalInfo();
if (lvt != null) {
LocalVariableInfo lvi = findLVTEntry(lvt, slot, 0);
if (lvi != null) {
local.name = lvi.name;
}
}
local.type = paramTypes[i].getTypeSignature();
local.size = paramTypes[i].stackSize();
paramLocals[slot] = local;
slot += local.size;
}
}
/* Initialize the InstrInfos and LocalInfos /* Initialize the InstrInfos and LocalInfos
*/ */
changedInfos = new Stack(); changedInfos = new Stack();
@ -335,8 +322,7 @@ public class LocalOptimizer implements Opcodes {
while (true) { while (true) {
instrInfos.put(instr, info); instrInfos.put(instr, info);
info.instr = instr; info.instr = instr;
info.nextReads = new LocalInfo[maxlocals]; info.nextReads = new InstrInfo[maxlocals];
info.belongsToJsrs = new Vector[maxlocals];
if (instr.localSlot != -1) { if (instr.localSlot != -1) {
info.local = new LocalInfo(info); info.local = new LocalInfo(info);
if (lvt != null) { if (lvt != null) {
@ -354,14 +340,14 @@ public class LocalOptimizer implements Opcodes {
case opc_iload: case opc_fload: case opc_aload: case opc_iload: case opc_fload: case opc_aload:
case opc_iinc: case opc_iinc:
/* this is a load instruction */ /* this is a load instruction */
info.nextReads[instr.localSlot] = info.local; info.nextReads[instr.localSlot] = info;
changedInfos.push(info); changedInfos.push(info);
break; break;
case opc_ret: case opc_ret:
/* this is a ret instruction */ /* this is a ret instruction */
info.local.retInfo = info; info.usedBySub = new BitSet();
info.nextReads[instr.localSlot] = info.local; info.nextReads[instr.localSlot] = info;
changedInfos.push(info); changedInfos.push(info);
break; break;
@ -376,16 +362,26 @@ public class LocalOptimizer implements Opcodes {
} }
} }
// for (InstrInfo info = firstInfo; info != null; info = info.nextInfo)
// if (info.instr.opcode == opc_jsr)
// analyzeSubRoutine(info.succs[0]);
/* find out which locals are the same. /* find out which locals are the same.
*/ */
while (!changedInfos.isEmpty()) { while (!changedInfos.isEmpty()) {
InstrInfo info = (InstrInfo) changedInfos.pop(); InstrInfo info = (InstrInfo) changedInfos.pop();
Instruction instr = info.instr; Instruction instr = info.instr;
/* Mark the local as used in all ret instructions */
if (instr.localSlot != -1) {
for (int i=0; i< maxlocals; i++) {
InstrInfo retInfo = info.nextReads[i];
if (retInfo != null && retInfo.instr.opcode == opc_ret
&& !retInfo.usedBySub.get(instr.localSlot)) {
retInfo.usedBySub.set(instr.localSlot);
if (retInfo.jsrTargetInfo != null)
changedInfos.push(retInfo.jsrTargetInfo);
}
}
}
Instruction prevInstr = instr.prevByAddr; Instruction prevInstr = instr.prevByAddr;
if (prevInstr != null) { if (prevInstr != null) {
if (prevInstr.opcode == opc_jsr) { if (prevInstr.opcode == opc_jsr) {
@ -394,21 +390,26 @@ public class LocalOptimizer implements Opcodes {
*/ */
InstrInfo jsrInfo = InstrInfo jsrInfo =
(InstrInfo) instrInfos.get(prevInstr.succs[0]); (InstrInfo) instrInfos.get(prevInstr.succs[0]);
if (jsrInfo.retInstr != null) if (jsrInfo.retInfo != null) {
promoteReads(info, jsrInfo.retInstr); /* Now promote reads that are modified by the
* subroutine to the ret, and those that are not
/* Now promote reads that aren't modified by the * to the jsr instruction.
* subroutine to prevInstr */
*/ promoteReads(info, jsrInfo.retInfo.instr,
promoteSubRoutineReads(info, prevInstr, jsrInfo); jsrInfo.retInfo.usedBySub, false);
promoteReads(info, prevInstr,
jsrInfo.retInfo.usedBySub, true);
}
} else if (!prevInstr.alwaysJumps) } else if (!prevInstr.alwaysJumps)
promoteReads(info, prevInstr); promoteReads(info, prevInstr);
} }
if (instr.preds != null) { if (instr.preds != null) {
for (int i = 0; i < instr.preds.length; i++) { for (int i = 0; i < instr.preds.length; i++) {
Instruction predInstr = instr.preds[i];
if (instr.preds[i].opcode == opc_jsr) { if (instr.preds[i].opcode == opc_jsr) {
/* This is the target of a jsr instr.
*/
if (info.instr.opcode != opc_astore) { if (info.instr.opcode != opc_astore) {
/* XXX Grrr, the bytecode verifier doesn't /* XXX Grrr, the bytecode verifier doesn't
* test if a jsr starts with astore. So * test if a jsr starts with astore. So
@ -417,13 +418,34 @@ public class LocalOptimizer implements Opcodes {
* local. */ * local. */
throw new AssertError("Non standard jsr"); throw new AssertError("Non standard jsr");
} }
LocalInfo local = info.nextReads[info.instr.localSlot]; InstrInfo retInfo
if (local != null && local.retInfo != null) { = info.nextReads[info.instr.localSlot];
info.retInstr = local.retInfo.instr;
/*XXX*/ if (retInfo != null) {
if (retInfo.instr.opcode != opc_ret)
throw new AssertError
("reading return address");
info.retInfo = retInfo;
retInfo.jsrTargetInfo = info;
/* Now promote reads from the instruction
* after the jsr to the ret instruction if
* they are modified by the subroutine,
* and to the jsr instruction otherwise.
*/
Instruction nextInstr = predInstr.nextByAddr;
InstrInfo nextInfo
= (InstrInfo) instrInfos.get(nextInstr);
promoteReads(nextInfo, retInfo.instr,
retInfo.usedBySub, false);
promoteReads(nextInfo, predInstr,
retInfo.usedBySub, true);
} }
} } else
promoteReads(info, instr.preds[i]); promoteReads(info, instr.preds[i]);
} }
} }
@ -438,6 +460,16 @@ public class LocalOptimizer implements Opcodes {
} }
} }
changedInfos = null; changedInfos = null;
/* Now merge with the parameters
* The params should be the locals in firstInfo.nextReads
*/
for (int i=0; i< paramLocals.length; i++) {
if (firstInfo.nextReads[i] != null) {
firstInfo.nextReads[i].local.combineInto(paramLocals[i]);
paramLocals[i] = paramLocals[i].getReal();
}
}
} }
public void stripLocals() { public void stripLocals() {
@ -524,12 +556,10 @@ public class LocalOptimizer implements Opcodes {
*/ */
/* first give the params the same slot as they had before. /* first give the params the same slot as they had before.
* The params should be the locals in firstInfo.nextReads
*/ */
for (int i=0; i< maxlocals; i++) { for (int i=0; i<paramLocals.length; i++)
if (firstInfo.nextReads[i] != null) if (paramLocals[i] != null)
firstInfo.nextReads[i].getReal().newSlot = i; paramLocals[i].newSlot = i;
}
/* Now calculate the conflict settings. /* Now calculate the conflict settings.
*/ */
@ -543,7 +573,7 @@ public class LocalOptimizer implements Opcodes {
for (int i=0; i < maxlocals; i++) { for (int i=0; i < maxlocals; i++) {
if (i != info.instr.localSlot if (i != info.instr.localSlot
&& info.nextReads[i] != null) && info.nextReads[i] != null)
info.local.conflictsWith(info.nextReads[i]); info.local.conflictsWith(info.nextReads[i].local);
} }
} }
} }
@ -564,7 +594,7 @@ public class LocalOptimizer implements Opcodes {
/* Update the instructions and calculate new maxlocals. /* Update the instructions and calculate new maxlocals.
*/ */
maxlocals = paramCount; maxlocals = paramLocals.length;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) { if (info.local != null) {
if (info.local.newSlot+info.local.size > maxlocals) if (info.local.newSlot+info.local.size > maxlocals)
@ -580,94 +610,168 @@ public class LocalOptimizer implements Opcodes {
buildNewLVT(); buildNewLVT();
} }
private LocalInfo CONFLICT = new LocalInfo(); private InstrInfo CONFLICT = new InstrInfo();
void promoteValues(InstrInfo info, Instruction nextInstr) { boolean promoteLifeLocals(LocalInfo[] newLife, InstrInfo nextInfo) {
Instruction instr = info.instr; if (nextInfo.lifeLocals == null) {
InstrInfo nextInfo = (InstrInfo) instrInfos.get(nextInstr); nextInfo.lifeLocals = (LocalInfo[]) newLife.clone();
return true;
}
boolean changed = false;
for (int i=0; i< maxlocals; i++) { for (int i=0; i< maxlocals; i++) {
LocalInfo local = info.nextReads[i]; LocalInfo local = nextInfo.lifeLocals[i];
if (local != null) if (local == null)
local = local.getReal(); /* A conflict has already happened, or this slot
if (instr.localSlot == i * may not have been initialized. */
&& instr.opcode >= opc_istore continue;
&& instr.opcode <= opc_astore)
local = info.local; local = local.getReal();
LocalInfo newLocal = newLife[i];
if (nextInfo.nextReads[i] == null) if (newLocal != null)
nextInfo.nextReads[i] = local; newLocal = newLocal.getReal();
else if (local != null if (local != newLocal) {
&& local != nextInfo.nextReads[i].getReal()) nextInfo.lifeLocals[i] = null;
nextInfo.nextReads[i] = CONFLICT; changed = true;
}
} }
return changed;
} }
public void buildNewLVT() { public void buildNewLVT() {
/* We reuse the nextReads array for a differen purpose. /* First we recalculate the usedBySub, to use the new local numbers.
* For every slot we remember in this array, which local is
* there
* find out how long they remain there value.
*/ */
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo)
if (info.usedBySub != null)
info.usedBySub = new BitSet();
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
if (info.local != null) {
for (int i=0; i < info.nextReads.length; i++) {
if (info.nextReads[i] != null
&& info.nextReads[i].instr.opcode == opc_ret)
info.nextReads[i].usedBySub.set(info.local.newSlot);
}
}
}
/* Now we begin with the first Instruction and follow program flow.
* We remember which locals are life in lifeLocals.
*/
firstInfo.lifeLocals = new LocalInfo[maxlocals];
for (int i=0; i < paramLocals.length; i++)
firstInfo.lifeLocals[i] = paramLocals[i];
Stack changedInfo = new Stack(); Stack changedInfo = new Stack();
changedInfo.push(firstInfo);
Handler[] handlers = bc.getExceptionHandlers(); Handler[] handlers = bc.getExceptionHandlers();
for (InstrInfo info = firstInfo;
info != null; info = info.nextInfo)
changedInfo.push(info);
while (!changedInfo.isEmpty()) { while (!changedInfo.isEmpty()) {
InstrInfo info = (InstrInfo) changedInfo.pop(); InstrInfo info = (InstrInfo) changedInfo.pop();
Instruction instr = info.instr; Instruction instr = info.instr;
if (!instr.alwaysJumps) { LocalInfo[] newLife = info.lifeLocals;
Instruction nextInstr = instr.nextByAddr; if (instr.localSlot != -1) {
promoteValues(info, instr.nextByAddr); LocalInfo instrLocal = info.local.getReal();
newLife = (LocalInfo[]) newLife.clone();
newLife[instr.localSlot] = instrLocal;
if (instrLocal.name != null) {
for (int j=0; j< newLife.length; j++) {
if (j != instr.localSlot
&& newLife[j] != null
&& instrLocal.name.equals(newLife[j].name)) {
/* This local changed the slot. */
newLife[j] = null;
}
}
}
} }
if (!instr.alwaysJumps) {
InstrInfo nextInfo = info.nextInfo;
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
if (instr.succs != null) { if (instr.succs != null) {
for (int i = 0; i < instr.succs.length; i++) for (int i = 0; i < instr.succs.length; i++) {
promoteValues(info, instr.succs[i]); InstrInfo nextInfo
= (InstrInfo) instrInfos.get(instr.succs[i]);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
} }
for (int i=0; i < handlers.length; i++) { for (int i=0; i < handlers.length; i++) {
if (handlers[i].start.addr >= instr.addr if (handlers[i].start.addr <= instr.addr
&& handlers[i].end.addr <= instr.addr) && handlers[i].end.addr >= instr.addr) {
promoteValues(info, handlers[i].catcher); InstrInfo nextInfo
= (InstrInfo) instrInfos.get(handlers[i].catcher);
if (promoteLifeLocals(newLife, nextInfo))
changedInfo.push(nextInfo);
}
}
if (instr.opcode == opc_ret) {
/* On a ret we do a special merge */
Instruction jsrTargetInstr = info.jsrTargetInfo.instr;
for (int j=0; j< jsrTargetInstr.preds.length; j++) {
InstrInfo jsrInfo
= (InstrInfo) instrInfos.get(jsrTargetInstr.preds[j]);
LocalInfo[] retLife = (LocalInfo[]) newLife.clone();
for (int i=0; i< maxlocals; i++) {
if (!info.usedBySub.get(i))
retLife[i] = jsrInfo.lifeLocals[i];
}
if (promoteLifeLocals(retLife, jsrInfo.nextInfo))
changedInfo.push(jsrInfo.nextInfo);
}
} }
} }
Vector lvtEntries = new Vector(); Vector lvtEntries = new Vector();
LocalVariableInfo[] lvi = new LocalVariableInfo[maxlocals]; LocalVariableInfo[] lvi = new LocalVariableInfo[maxlocals];
LocalInfo[] currentLocal = new LocalInfo[maxlocals]; LocalInfo[] currentLocal = new LocalInfo[maxlocals];
for (int i=0; i< paramLocals.length; i++) {
if (paramLocals[i] != null) {
currentLocal[i] = paramLocals[i];
if (currentLocal[i].name != null) {
lvi[i] = new LocalVariableInfo();
lvtEntries.addElement(lvi[i]);
lvi[i].name = currentLocal[i].name;
lvi[i].type = currentLocal[i].type;
lvi[i].start = bc.getFirstInstr();
lvi[i].slot = i;
}
}
}
Instruction lastInstr = null; Instruction lastInstr = null;
for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) { for (InstrInfo info = firstInfo; info != null; info = info.nextInfo) {
for (int i=0; i< maxlocals; i++) { for (int i=0; i< maxlocals; i++) {
LocalInfo lcl = info.nextReads[i]; LocalInfo lcl = info.lifeLocals != null ? info.lifeLocals[i]
if (lcl == CONFLICT) : null;
lcl = null; if (lcl != currentLocal[i]
else if (lcl != null) && (lcl == null || currentLocal[i] == null
lcl = lcl.getReal(); || !lcl.name.equals(currentLocal[i].name)
if (lcl != currentLocal[i]) { || !lcl.type.equals(currentLocal[i].type))) {
if (lvi[i] != null) { if (lvi[i] != null) {
lvi[i].end = info.instr.prevByAddr; lvi[i].end = info.instr.prevByAddr;
lvtEntries.addElement(lvi[i]);
} }
lvi[i] = null; lvi[i] = null;
currentLocal[i] = lcl; currentLocal[i] = lcl;
if (currentLocal[i] != null if (currentLocal[i] != null
&& currentLocal[i].name != null) { && currentLocal[i].name != null) {
lvi[i] = new LocalVariableInfo(); lvi[i] = new LocalVariableInfo();
lvtEntries.addElement(lvi[i]);
lvi[i].name = currentLocal[i].name; lvi[i].name = currentLocal[i].name;
lvi[i].type = currentLocal[i].type; lvi[i].type = currentLocal[i].type;
lvi[i].start = info.instr; lvi[i].start = info.instr;
lvi[i].slot = i; lvi[i].slot = i;
} }
changedInfo.push(info);
} }
} }
lastInstr = info.instr; lastInstr = info.instr;
} }
for (int i=0; i< maxlocals; i++) { for (int i=0; i< maxlocals; i++) {
if (lvi[i] != null) { if (lvi[i] != null)
lvi[i].end = lastInstr; lvi[i].end = lastInstr;
lvtEntries.addElement(lvi[i]);
}
} }
LocalVariableInfo[] lvt = new LocalVariableInfo[lvtEntries.size()]; LocalVariableInfo[] lvt = new LocalVariableInfo[lvtEntries.size()];
lvtEntries.copyInto(lvt); lvtEntries.copyInto(lvt);

Loading…
Cancel
Save