Initial revision

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@448 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 26 years ago
parent 4a40e01fac
commit 1d77b7ad18
  1. 645
      jode/jode/bytecode/BytecodeInfo.java
  2. 10
      jode/jode/bytecode/Handler.java
  3. 73
      jode/jode/bytecode/Instruction.java
  4. 97
      jode/jode/decompiler/DeadCodeAnalysis.java

@ -0,0 +1,645 @@
package jode.bytecode;
import jode.Decompiler/*XXX*/;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.EOFException;
import java.io.IOException;
import java.util.Vector;
public class BytecodeInfo extends BinaryInfo implements Opcodes {
ConstantPool cp;
int maxStack, maxLocals;
Instruction firstInstr = null;
Handler[] exceptionHandlers;
private final static Object[] constants = {
null,
new Integer(-1), new Integer(0), new Integer(1),
new Integer(2), new Integer(3), new Integer(4), new Integer(5),
new Long(0), new Long(1),
new Float(0), new Float(1), new Float(2),
new Double(0), new Double(1)
};
public void read(ConstantPool cp,
DataInputStream input) throws IOException {
this.cp = cp;
maxStack = input.readUnsignedShort();
maxLocals = input.readUnsignedShort();
int codeLength = input.readInt();
Instruction[] instrs = new Instruction[codeLength];
int[][] succAddrs = new int[codeLength][];
{
int addr = 0;
Instruction lastInstr = null;
while (addr < codeLength) {
Instruction instr = new Instruction();
if (lastInstr != null) {
lastInstr.nextByAddr = instr;
instr.prevByAddr = lastInstr;
}
instrs[addr] = instr;
instr.addr = addr;
lastInstr = instr;
int opcode = input.readUnsignedByte();
if (Decompiler.isDebugging)/*XXX*/
Decompiler.err.println(addr+": "+opcodeString[opcode]);
instr.opcode = opcode;
switch (opcode) {
case opc_wide: {
int wideopcode = input.readUnsignedByte();
instr.opcode = wideopcode;
switch (wideopcode) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
instr.localSlot = input.readUnsignedShort();
instr.length = 4;
break;
case opc_ret:
instr.localSlot = input.readUnsignedShort();
instr.length = 4;
instr.alwaysJumps = true;
break;
case opc_iinc:
instr.localSlot = input.readUnsignedShort();
instr.intData = input.readShort();
instr.length = 6;
break;
default:
throw new ClassFormatError("Invalid wide opcode "
+wideopcode);
}
break;
}
case opc_iload_0: case opc_iload_1:
case opc_iload_2: case opc_iload_3:
case opc_lload_0: case opc_lload_1:
case opc_lload_2: case opc_lload_3:
case opc_fload_0: case opc_fload_1:
case opc_fload_2: case opc_fload_3:
case opc_dload_0: case opc_dload_1:
case opc_dload_2: case opc_dload_3:
case opc_aload_0: case opc_aload_1:
case opc_aload_2: case opc_aload_3:
instr.opcode = opc_iload + (opcode-opc_iload_0)/4;
instr.localSlot = (opcode-opc_iload_0) & 3;
instr.length = 1;
break;
case opc_istore_0: case opc_istore_1:
case opc_istore_2: case opc_istore_3:
case opc_lstore_0: case opc_lstore_1:
case opc_lstore_2: case opc_lstore_3:
case opc_fstore_0: case opc_fstore_1:
case opc_fstore_2: case opc_fstore_3:
case opc_dstore_0: case opc_dstore_1:
case opc_dstore_2: case opc_dstore_3:
case opc_astore_0: case opc_astore_1:
case opc_astore_2: case opc_astore_3:
instr.opcode = opc_istore + (opcode-opc_istore_0)/4;
instr.localSlot = (opcode-opc_istore_0) & 3;
instr.length = 1;
break;
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
instr.localSlot = input.readUnsignedByte();
instr.length = 2;
break;
case opc_ret:
instr.localSlot = input.readUnsignedByte();
instr.alwaysJumps = true;
instr.length = 2;
break;
case opc_aconst_null:
case opc_iconst_m1:
case opc_iconst_0: case opc_iconst_1: case opc_iconst_2:
case opc_iconst_3: case opc_iconst_4: case opc_iconst_5:
case opc_lconst_0: case opc_lconst_1:
case opc_fconst_0: case opc_fconst_1: case opc_fconst_2:
case opc_dconst_0: case opc_dconst_1:
instr.objData = constants[instr.opcode - opc_aconst_null];
instr.length = 1;
break;
case opc_bipush:
instr.objData = new Integer(input.readByte());
instr.length = 2;
break;
case opc_sipush:
instr.objData = new Integer(input.readShort());
instr.length = 3;
break;
case opc_ldc:
instr.objData = cp.getConstant(input.readUnsignedByte());
instr.length = 2;
break;
case opc_ldc_w:
instr.opcode = opc_ldc;
/* fall through */
case opc_ldc2_w:
instr.objData = cp.getConstant(input.readUnsignedShort());
instr.length = 3;
break;
case opc_iinc:
instr.localSlot = input.readUnsignedByte();
instr.intData = input.readByte();
instr.length = 3;
break;
case opc_goto:
instr.alwaysJumps = true;
/* fall through */
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
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_ifnull: case opc_ifnonnull:
case opc_jsr:
succAddrs[addr] = new int[1];
succAddrs[addr][0] = addr+input.readShort();
instr.length = 3;
break;
case opc_goto_w:
instr.alwaysJumps = true;
/* fall through */
case opc_jsr_w:
instr.opcode -= opc_goto_w - opc_goto;
succAddrs[addr] = new int[1];
succAddrs[addr][0] = addr+input.readInt();
instr.length = 5;
break;
case opc_tableswitch: {
int length = 3-(addr % 4);
input.readFully(new byte[length]);
int def = input.readInt();
int low = input.readInt();
int high = input.readInt();
instr.intData = low;
succAddrs[addr] = new int[high-low+2];
for (int i=0; i+low <= high; i++) {
succAddrs[addr][i] = addr + input.readInt();
}
succAddrs[addr][high-low+1] = addr + def;
instr.alwaysJumps = true;
instr.length = length + 13 + 4 * (high-low+1);
break;
}
case opc_lookupswitch: {
int length = 3-(addr % 4);
input.readFully(new byte[length]);
int def = input.readInt();
int npairs = input.readInt();
succAddrs[addr] = new int[npairs + 1];
int[] values = new int[npairs];
for (int i=0; i < npairs; i++) {
values[i] = input.readInt();
succAddrs[addr][i] = addr + input.readInt();
}
succAddrs[addr][npairs] = addr + def;
instr.objData = values;
instr.alwaysJumps = true;
instr.length = length + 9 + 8 * npairs;
break;
}
case opc_ireturn: case opc_lreturn:
case opc_freturn: case opc_dreturn: case opc_areturn:
case opc_return:
case opc_athrow:
instr.alwaysJumps = true;
instr.length = 1;
break;
case opc_getstatic:
case opc_getfield:
case opc_putstatic:
case opc_putfield:
case opc_invokespecial:
case opc_invokestatic:
case opc_invokevirtual:
instr.objData = cp.getRef(input.readUnsignedShort());
instr.length = 3;
break;
case opc_invokeinterface:
instr.objData = cp.getRef(input.readUnsignedShort());
instr.intData = input.readUnsignedShort();
instr.length = 5;
break;
case opc_new:
case opc_anewarray:
case opc_checkcast:
case opc_instanceof:
instr.objData = cp.getClassName(input.readUnsignedShort())
.replace('/','.');
instr.length = 3;
break;
case opc_multianewarray:
instr.objData = cp.getClassName(input.readUnsignedShort())
.replace('/','.');
instr.intData = input.readUnsignedByte();
instr.length = 4;
break;
case opc_newarray:
instr.intData = input.readUnsignedByte();
instr.length = 2;
break;
default:
if (opcode == opc_xxxunusedxxx
|| opcode >= opc_breakpoint)
throw new ClassFormatError("Invalid opcode "+opcode);
else
instr.length = 1;
}
addr += lastInstr.length;
}
}
firstInstr = instrs[0];
for (Instruction instr = firstInstr;
instr != null; instr = instr.nextByAddr) {
int addr = instr.addr;
if (succAddrs[addr] != null) {
int length = succAddrs[addr].length;
instr.succs = new Instruction[length];
for (int i=0; i < length; i++) {
instr.succs[i] = instrs[succAddrs[addr][i]];
instr.succs[i].preds.addElement(instr);
}
}
/* YES, if the last instruction is not reachable it may
* not alwaysJump. This happens under jikes
*/
if (!instr.alwaysJumps && instr.nextByAddr != null)
instr.nextByAddr.preds.addElement(instr);
}
succAddrs = null;
{
int handlersLength = input.readUnsignedShort();
exceptionHandlers = new Handler[handlersLength];
for (int i=0; i< handlersLength; i ++) {
exceptionHandlers[i] = new Handler();
exceptionHandlers[i].start
= instrs[input.readUnsignedShort()];
exceptionHandlers[i].end
= instrs[input.readUnsignedShort()].prevByAddr;
exceptionHandlers[i].catcher
= instrs[input.readUnsignedShort()];
int index = input.readUnsignedShort();
exceptionHandlers[i].type = (index == 0) ? null
: cp.getClassName(index).replace('/','.');
}
}
readAttributes(cp, input, FULLINFO);
}
public void writeCode(GrowableConstantPool gcp,
jode.obfuscator.ClassBundle bundle,
DataOutputStream output) throws IOException {
/* Recalculate addr and length */
int addr = 0;
for (Instruction instr = firstInstr;
instr != null; instr = instr.nextByAddr) {
instr.addr = addr;
if (instr.opcode == opc_ldc) {
if (gcp.reserveConstant(instr.objData) < 256)
instr.length = 2;
else
instr.length = 3;
// if (instr.objData == null) {
// instr.length = 1;
// } else if (instr.objData instanceof Integer) {
// int value = ((Integer) instr.objData).intValue();
// if (value >= -1 && value <= 5)
// instr.length = 1;
// else if (value >= -Byte.MIN_VALUE
// && value <= Byte.MAX_VALUE)
// instr.length = 2;
// else if (value >= -Short.MIN_VALUE
// && value <= Short.MAX_VALUE)
// instr.length = 3;
// else if (gcp.reserveConstant(instr.objData) < 256)
// instr.length = 2;
// else
// instr.length = 3;
// } else if (instr.objData instanceof Long) {
// long value = ((Long) instr.objData).longValue();
// if (value == 0L || value == 1L)
// instr.length = 1;
// else
// instr.length = 3;
// } else if (instr.objData instanceof Float) {
// float value = ((Float) instr.objData).floatValue();
// if (value == 0.0F || value == 1.0F)
// instr.length = 1;
// else if (gcp.reserveConstant(instr.objData) < 256)
// instr.length = 2;
// else
// instr.length = 3;
// } else if (instr.objData instanceof Double) {
// double value = ((Double) instr.objData).doubleValue();
// if (value == 0.0 || value == 1.0)
// instr.length = 1;
// else
// instr.length = 3;
// } else {
// if (gcp.reserveConstant(instr.objData) < 256)
// instr.length = 2;
// else
// instr.length = 3;
// }
} else if (instr.localSlot != -1) {
if (instr.opcode == opc_iinc) {
if (instr.localSlot < 256
&& instr.intData >= Byte.MIN_VALUE
&& instr.intData <= Byte.MAX_VALUE)
instr.length = 3;
else
instr.length = 6;
} else {
if (instr.localSlot < 4)
instr.length = 1;
else if (instr.localSlot < 256)
instr.length = 2;
else
instr.length = 4;
}
} else if (instr.opcode == opc_tableswitch) {
int length = 3-(addr % 4);
instr.length = length + 9 + 4 * instr.succs.length;
} else if (instr.opcode == opc_lookupswitch) {
int length = 3-(addr % 4);
instr.length = length + 1 + 8 * instr.succs.length;
} else if (instr.opcode == opc_goto
|| instr.opcode == opc_jsr) {
int dist = instr.succs[0].addr - instr.addr;
if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) {
instr.length = 5;
} else
instr.length = 3;
}
addr += instr.length;
}
/* Now output the code */
output.writeShort(maxStack);
output.writeShort(maxLocals);
output.writeInt(addr);
for (Instruction instr = firstInstr;
instr != null; instr = instr.nextByAddr) {
switch (instr.opcode) {
case opc_iload: case opc_lload:
case opc_fload: case opc_dload: case opc_aload:
case opc_istore: case opc_lstore:
case opc_fstore: case opc_dstore: case opc_astore:
if (instr.length == 1) {
if (instr.opcode < opc_istore)
output.writeByte(opc_iload_0
+ 4*(instr.opcode-opc_iload)
+ instr.localSlot);
else
output.writeByte(opc_istore_0
+ 4*(instr.opcode-opc_istore)
+ instr.localSlot);
} else if (instr.length == 2) {
output.writeByte(instr.opcode);
output.writeByte(instr.localSlot);
} else {
output.writeByte(opc_wide);
output.writeByte(instr.opcode);
output.writeShort(instr.localSlot);
}
break;
case opc_ret:
if (instr.length == 2) {
output.writeByte(instr.opcode);
output.writeByte(instr.localSlot);
} else {
output.writeByte(opc_wide);
output.writeByte(instr.opcode);
output.writeShort(instr.localSlot);
}
break;
case opc_ldc:
// if (instr.objData == null)
// output.writeByte(opc_aconst_null);
// else if (instr.length == 1) {
// int value = ((Number) instr.objData).intValue();
// if (instr.objData instanceof Integer)
// output.writeByte(opc_iconst_0+value);
// else if (instr.objData instanceof Long)
// output.writeByte(opc_lconst_0+value);
// else if (instr.objData instanceof Float)
// output.writeByte(opc_fconst_0+value);
// else if (instr.objData instanceof Double)
// output.writeByte(opc_dconst_0+value);
// } else if (instr.objData instanceof Long
// || instr.objData instanceof Double) {
// output.writeByte(opc_ldc2_w);
// output.writeShort(gcp.putConstant(instr.objData));
// } else {
// if (instr.objData instanceof Integer) {
// int value = ((Integer) instr.objData).intValue();
// if (value >= -Byte.MIN_VALUE
// && value <= Byte.MAX_VALUE) {
// output.writeByte(opc_bipush);
// output.writeByte(value);
// break;
// } else if (value >= -Short.MIN_VALUE
// && value <= Short.MAX_VALUE) {
// output.writeByte(opc_sipush);
// output.writeShort(value);
// break;
// }
// }
if (instr.length == 2) {
output.writeByte(opc_ldc);
output.writeByte(gcp.putConstant(instr.objData));
} else {
output.writeByte(opc_ldc_w);
output.writeShort(gcp.putConstant(instr.objData));
}
break;
case opc_ldc2_w:
output.writeByte(instr.opcode);
output.writeShort(gcp.putConstant(instr.objData));
break;
case opc_bipush:
output.writeByte(instr.opcode);
output.writeByte(((Integer)instr.objData).intValue());
break;
case opc_sipush:
output.writeByte(instr.opcode);
output.writeShort(((Integer)instr.objData).intValue());
break;
case opc_iinc:
if (instr.length == 3) {
output.writeByte(instr.opcode);
output.writeByte(instr.localSlot);
output.writeByte(instr.intData);
} else {
output.writeByte(opc_wide);
output.writeByte(instr.opcode);
output.writeShort(instr.localSlot);
output.writeShort(instr.intData);
}
break;
case opc_goto:
case opc_ifeq: case opc_ifne:
case opc_iflt: case opc_ifge:
case opc_ifgt: case opc_ifle:
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_ifnull: case opc_ifnonnull:
case opc_jsr:
if (instr.length == 3) {
output.writeByte(instr.opcode);
output.writeShort(instr.succs[0].addr - instr.addr);
} else {
/* wide goto or jsr */
output.writeByte(instr.opcode + (opc_goto_w - opc_goto));
output.writeInt(instr.succs[0].addr - instr.addr);
}
break;
case opc_tableswitch: {
output.writeByte(instr.opcode);
int align = 3-(instr.addr % 4);
int numcases = instr.succs.length - 1;
output.write(new byte[align]);
/* def */
output.writeInt(instr.succs[numcases].addr - instr.addr);
/* low */
output.writeInt(instr.intData);
/* high */
output.writeInt(instr.intData + numcases - 1);
for (int i=0; i < numcases; i++)
output.writeInt(instr.succs[i].addr - instr.addr);
break;
}
case opc_lookupswitch: {
output.writeByte(instr.opcode);
int[] values = (int[]) instr.objData;
int align = 3-(instr.addr % 4);
int numcases = values.length;
output.write(new byte[align]);
/* def */
output.writeInt(instr.succs[numcases].addr - instr.addr);
output.writeInt(numcases);
for (int i=0; i < numcases; i++) {
output.writeInt(values[i]);
output.writeInt(instr.succs[i].addr - instr.addr);
}
break;
}
case opc_getstatic:
case opc_getfield:
case opc_putstatic:
case opc_putfield:
output.writeByte(instr.opcode);
output.writeShort(gcp.putRef(gcp.FIELDREF,
(String[]) instr.objData));
break;
case opc_invokespecial:
case opc_invokestatic:
case opc_invokeinterface:
case opc_invokevirtual:
output.writeByte(instr.opcode);
if (instr.opcode == opc_invokeinterface) {
output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF,
(String[]) instr.objData));
output.writeShort(instr.intData);
} else
output.writeShort(gcp.putRef(gcp.METHODREF,
(String[]) instr.objData));
break;
case opc_new:
case opc_anewarray:
case opc_checkcast:
case opc_instanceof:
case opc_multianewarray:
output.writeByte(instr.opcode);
output.writeShort(gcp.putClassRef((String) instr.objData));
if (instr.opcode == opc_multianewarray)
output.writeByte(instr.intData);
break;
case opc_newarray:
output.writeByte(instr.opcode);
output.writeByte(instr.intData);
break;
default:
if (instr.opcode == opc_xxxunusedxxx
|| instr.opcode >= opc_breakpoint)
throw new ClassFormatError("Invalid opcode "+instr.opcode);
else
output.writeByte(instr.opcode);
}
}
output.writeShort(exceptionHandlers.length);
for (int i=0; i< exceptionHandlers.length; i++) {
output.writeShort(exceptionHandlers[i].start.addr);
output.writeShort(exceptionHandlers[i].end.nextByAddr.addr);
output.writeShort(exceptionHandlers[i].catcher.addr);
output.writeShort((exceptionHandlers[i].type == null) ? 0
: gcp.putClassRef(exceptionHandlers[i].type));
}
output.writeShort(0); // No Attributes;
}
public int getMaxStack() {
return maxStack;
}
public int getMaxLocals() {
return maxLocals;
}
public Instruction getFirstInstr() {
return firstInstr;
}
public Handler[] getExceptionHandlers() {
return exceptionHandlers;
}
public void setExceptionHandlers(Handler[] handlers) {
exceptionHandlers = handlers;
}
}

@ -0,0 +1,10 @@
package jode.bytecode;
/**
* A simple class containing the info about an exception handler
*/
public class Handler {
public Instruction start, end, catcher;
public String type;
}

@ -0,0 +1,73 @@
package jode.bytecode;
import java.util.Vector;
/**
* This class represents an instruction in the byte code.
*
* For simplicity currently most fields are public. You shouldn't change
* many of them, though.
*/
public class Instruction implements Opcodes{
/**
* The opcode of the instruction. We map some opcodes, e.g.
* <pre>
* iload_[0-3] -> iload, ldc_w -> ldc, wide iinc -> iinc.
* </pre>
*/
public int opcode;
/**
* If this opcode uses a local this gives the slot. This info is
* used when swapping locals.
*/
public int localSlot = -1;
/**
* Optional object data for this opcode. This is mostly used for
* method/field/class references, but also for a value array
* in a lookupswitch.
*/
public Object objData;
/**
* Optional integer data for this opcode. There are various uses
* for this.
*/
public int intData;
/**
* The address of this opcode.
*/
public int addr;
/**
* The length of this opcode. You shouldn't touch it, nor rely on
* it, since the length of some opcodes may change automagically
* (e.g. when changing localSlot iload_0 <-> iload 5)
*/
public int length;
/**
* If this is true, the instruction will never flow into the nextByAddr.
*/
public boolean alwaysJumps = false;
/**
* The successors of this opcodes, where flow may lead to
* (except that nextByAddr is implicit if !alwaysJump). The
* value null is equivalent to an empty array.
*/
public Instruction[] succs;
/**
* The predecessors of this opcode, including the prevByAddr, if
* that does not alwaysJump.
*/
public Vector preds = new Vector();
/**
* The next instruction in code order.
*/
public Instruction nextByAddr;
/**
* The previous instruction in code order, useful when changing
* the order.
*/
public Instruction prevByAddr;
/**
* You can use this field to add some info to each instruction.
*/
public Object tmpInfo;
}

@ -0,0 +1,97 @@
package jode.decompiler;
import jode.bytecode.BytecodeInfo;
import jode.bytecode.Instruction;
import jode.bytecode.Handler;
public class DeadCodeAnalysis {
private final static Object reachable = new Integer(1);
private final static Object reachChanged = new Integer(2);
private static void propagateReachability(Instruction firstInstr,
Instruction reachInstr) {
if (reachInstr.tmpInfo != null)
return;
reachInstr.tmpInfo = reachChanged;
boolean changed;
do {
changed = false;
for (Instruction instr = firstInstr;
instr != null; instr = instr.nextByAddr) {
if (instr.tmpInfo == reachChanged) {
changed = true;
instr.tmpInfo = reachable;
if (instr.succs != null)
for (int i=0; i< instr.succs.length; i++)
if (instr.succs[i].tmpInfo == null)
instr.succs[i].tmpInfo = reachChanged;
if (!instr.alwaysJumps && instr.nextByAddr != null)
if (instr.nextByAddr.tmpInfo == null)
instr.nextByAddr.tmpInfo = reachChanged;
}
}
} while (changed);
}
public static void removeDeadCode(BytecodeInfo code) {
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr)
instr.tmpInfo = null;
propagateReachability(code.getFirstInstr(), code.getFirstInstr());
Handler[] handlers = code.getExceptionHandlers();
boolean changed;
do {
changed = false;
for (int i=0; i < handlers.length; i++) {
if (handlers[i].catcher.tmpInfo == null) {
/* check if the try block is somewhere reachable
* and mark the catcher as reachable then.
*/
for (Instruction instr = handlers[i].start;
instr != null; instr = instr.nextByAddr) {
if (instr.tmpInfo != null) {
propagateReachability(code.getFirstInstr(),
handlers[i].catcher);
changed = true;
break;
}
if (instr == handlers[i].end)
break;
}
}
}
} while (changed);
/* Now remove the dead code */
for (Instruction instr = code.getFirstInstr();
instr != null; instr = instr.nextByAddr) {
if (instr.tmpInfo == null) {
/* first block is always reachable, so prevByAddr != null */
instr.prevByAddr.nextByAddr = instr.nextByAddr;
instr.nextByAddr.prevByAddr = instr.prevByAddr;
/* adjust length, since someon may rely on this */
instr.prevByAddr.length += instr.length;
}
}
for (int i=0; i< handlers.length; i++) {
/* A handler is not reachable iff the catcher is not reachable */
if (handlers[i].catcher.tmpInfo == null) {
/* This is very seldom, so we can make it slow */
Handler[] newHandlers = new Handler[handlers.length - 1];
System.arraycopy(handlers, 0, newHandlers, 0, i);
System.arraycopy(handlers, i+1, newHandlers, i,
handlers.length - (i+1));
handlers = newHandlers;
code.setExceptionHandlers(newHandlers);
i--;
} else {
/* This works! */
while (handlers[i].start.tmpInfo == null)
handlers[i].start = handlers[i].start.nextByAddr;
while (handlers[i].end.tmpInfo == null)
handlers[i].end = handlers[i].end.prevByAddr;
}
}
}
}
Loading…
Cancel
Save