You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1357 lines
41 KiB
1357 lines
41 KiB
26 years ago
|
/* BytecodeInfo Copyright (C) 1999 Jochen Hoenicke.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||
|
* any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; see the file COPYING. If not, write to
|
||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*
|
||
|
* $Id$
|
||
|
*/
|
||
|
|
||
26 years ago
|
package jode.bytecode;
|
||
25 years ago
|
import jode.GlobalOptions;
|
||
26 years ago
|
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;
|
||
26 years ago
|
import java.util.Enumeration;
|
||
25 years ago
|
import java.util.NoSuchElementException;
|
||
|
|
||
25 years ago
|
import @COLLECTIONS@.Collection;
|
||
|
import @COLLECTIONS@.AbstractCollection;
|
||
|
import @COLLECTIONS@.Iterator;
|
||
25 years ago
|
|
||
26 years ago
|
|
||
|
/**
|
||
|
* This class represents the byte code of a method. Each instruction is
|
||
|
* stored in an Instruction instance.
|
||
|
*
|
||
25 years ago
|
* We canonicalize some opcodes: wide opcodes are mapped to short ones,
|
||
26 years ago
|
* opcodes that load a constant are mapped to opc_ldc or opc_ldc2_w, and
|
||
|
* opc_xload_x / opc_xstore_x opcodes are mapped to opc_xload / opc_xstore.
|
||
|
*/
|
||
26 years ago
|
public class BytecodeInfo extends BinaryInfo implements Opcodes {
|
||
|
|
||
26 years ago
|
MethodInfo methodInfo;
|
||
|
|
||
26 years ago
|
ConstantPool cp;
|
||
|
int maxStack, maxLocals;
|
||
26 years ago
|
int codeLength;
|
||
26 years ago
|
Instruction firstInstr = null;
|
||
25 years ago
|
int instructionCount = 0;
|
||
26 years ago
|
Handler[] exceptionHandlers;
|
||
26 years ago
|
LocalVariableInfo[] lvt;
|
||
|
LineNumber[] lnt;
|
||
|
|
||
|
public BytecodeInfo(MethodInfo mi) {
|
||
|
methodInfo = mi;
|
||
|
}
|
||
26 years ago
|
|
||
|
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)
|
||
|
};
|
||
|
|
||
26 years ago
|
protected void readAttribute(String name, int length, ConstantPool cp,
|
||
|
DataInputStream input,
|
||
|
int howMuch) throws IOException {
|
||
26 years ago
|
if ((howMuch & ALL_ATTRIBUTES) != 0
|
||
|
&& name.equals("LocalVariableTable")) {
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
|
||
|
GlobalOptions.err.println("LocalVariableTable of "+methodInfo.clazzInfo.getName() + "." + methodInfo.getName());
|
||
26 years ago
|
int count = input.readUnsignedShort();
|
||
|
if (length != 2 + count * 10) {
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
|
||
|
GlobalOptions.err.println("Illegal LVT length, ignoring it");
|
||
26 years ago
|
return;
|
||
|
}
|
||
|
lvt = new LocalVariableInfo[count];
|
||
|
for (int i=0; i < count; i++) {
|
||
|
lvt[i] = new LocalVariableInfo();
|
||
|
int start = input.readUnsignedShort();
|
||
|
int end = start + input.readUnsignedShort();
|
||
|
int nameIndex = input.readUnsignedShort();
|
||
|
int typeIndex = input.readUnsignedShort();
|
||
|
int slot = input.readUnsignedShort();
|
||
|
Instruction startInstr, endInstr;
|
||
|
for (startInstr = firstInstr;
|
||
25 years ago
|
startInstr.getAddr() < start && startInstr != null;
|
||
|
startInstr = startInstr.getNextByAddr()) {
|
||
26 years ago
|
/* empty */
|
||
|
}
|
||
|
endInstr = startInstr;
|
||
|
if (startInstr != null) {
|
||
25 years ago
|
while (endInstr.getNextByAddr() != null
|
||
|
&& endInstr.getNextByAddr().getAddr() < end)
|
||
|
endInstr = endInstr.getNextByAddr();
|
||
26 years ago
|
}
|
||
|
if (startInstr == null
|
||
25 years ago
|
|| startInstr.getAddr() != start
|
||
26 years ago
|
|| endInstr == null
|
||
25 years ago
|
|| endInstr.getAddr() + endInstr.getLength() != end
|
||
26 years ago
|
|| nameIndex == 0 || typeIndex == 0
|
||
|
|| slot >= maxLocals
|
||
|
|| cp.getTag(nameIndex) != cp.UTF8
|
||
|
|| cp.getTag(typeIndex) != cp.UTF8) {
|
||
|
|
||
|
// This is probably an evil lvt as created by HashJava
|
||
|
// simply ignore it.
|
||
25 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_LVT) != 0)
|
||
|
GlobalOptions.err.println
|
||
|
("Illegal entry, ignoring LVT");
|
||
26 years ago
|
lvt = null;
|
||
|
return;
|
||
|
}
|
||
|
lvt[i].start = startInstr;
|
||
|
lvt[i].end = endInstr;
|
||
|
lvt[i].name = cp.getUTF8(nameIndex);
|
||
|
lvt[i].type = cp.getUTF8(typeIndex);
|
||
|
lvt[i].slot = slot;
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
|
||
|
GlobalOptions.err.println("\t" + lvt[i].name + ": "
|
||
26 years ago
|
+ lvt[i].type
|
||
|
+" range "+start+" - "+end
|
||
|
+" slot "+slot);
|
||
|
}
|
||
26 years ago
|
} else if ((howMuch & ALL_ATTRIBUTES) != 0
|
||
|
&& name.equals("LineNumberTable")) {
|
||
26 years ago
|
int count = input.readUnsignedShort();
|
||
|
if (length != 2 + count * 4) {
|
||
26 years ago
|
GlobalOptions.err.println
|
||
26 years ago
|
("Illegal LineNumberTable, ignoring it");
|
||
|
return;
|
||
|
}
|
||
|
lnt = new LineNumber[count];
|
||
|
for (int i = 0; i < count; i++) {
|
||
|
lnt[i] = new LineNumber();
|
||
|
int start = input.readUnsignedShort();
|
||
|
Instruction startInstr;
|
||
|
for (startInstr = firstInstr;
|
||
25 years ago
|
startInstr.getAddr() < start && startInstr != null;
|
||
|
startInstr = startInstr.getNextByAddr()) {
|
||
26 years ago
|
/* empty */
|
||
|
}
|
||
|
if (startInstr == null
|
||
25 years ago
|
|| startInstr.getAddr() != start) {
|
||
26 years ago
|
GlobalOptions.err.println
|
||
26 years ago
|
("Illegal entry, ignoring LineNumberTable table");
|
||
|
lnt = null;
|
||
|
return;
|
||
|
}
|
||
|
lnt[i].start = startInstr;
|
||
|
lnt[i].linenr = input.readUnsignedShort();
|
||
|
}
|
||
|
} else
|
||
|
super.readAttribute(name, length, cp, input, howMuch);
|
||
|
}
|
||
|
|
||
26 years ago
|
public void read(ConstantPool cp,
|
||
|
DataInputStream input) throws IOException {
|
||
|
this.cp = cp;
|
||
|
maxStack = input.readUnsignedShort();
|
||
|
maxLocals = input.readUnsignedShort();
|
||
26 years ago
|
codeLength = input.readInt();
|
||
26 years ago
|
Instruction[] instrs = new Instruction[codeLength];
|
||
|
int[][] succAddrs = new int[codeLength][];
|
||
26 years ago
|
int[] predcounts = new int[codeLength];
|
||
26 years ago
|
{
|
||
|
int addr = 0;
|
||
25 years ago
|
firstInstr = new Instruction(this);
|
||
|
instructionCount++;
|
||
26 years ago
|
Instruction lastInstr = null;
|
||
|
while (addr < codeLength) {
|
||
25 years ago
|
Instruction instr = lastInstr != null
|
||
|
? lastInstr.appendInstruction(opc_nop) : firstInstr;
|
||
|
|
||
26 years ago
|
instrs[addr] = instr;
|
||
|
lastInstr = instr;
|
||
|
|
||
|
int opcode = input.readUnsignedByte();
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.print(addr+": "+opcodeString[opcode]);
|
||
26 years ago
|
|
||
|
switch (opcode) {
|
||
|
case opc_wide: {
|
||
|
int wideopcode = input.readUnsignedByte();
|
||
25 years ago
|
instr.replaceInstruction(wideopcode);
|
||
26 years ago
|
switch (wideopcode) {
|
||
26 years ago
|
case opc_iload: case opc_fload: case opc_aload:
|
||
25 years ago
|
case opc_istore: case opc_fstore: case opc_astore: {
|
||
|
int slot = input.readUnsignedShort();
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(4);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print
|
||
|
(" " + opcodeString[wideopcode] + " " + slot);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_lload: case opc_dload:
|
||
25 years ago
|
case opc_lstore: case opc_dstore: {
|
||
|
int slot = input.readUnsignedShort();
|
||
|
if (slot >= maxLocals-1)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(4);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.print(" "+opcodeString[wideopcode]
|
||
25 years ago
|
+" "+slot);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
|
case opc_ret: {
|
||
|
int slot = input.readUnsignedShort();
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(4);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" ret "+slot);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
|
case opc_iinc: {
|
||
|
int slot = input.readUnsignedShort();
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setIntData(input.readShort());
|
||
|
instr.setLength(6);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" iinc "+slot
|
||
|
+" "+instr.getIntData());
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
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:
|
||
25 years ago
|
case opc_aload_2: case opc_aload_3: {
|
||
|
int slot = (opcode-opc_iload_0) & 3;
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opc_iload +
|
||
|
(opcode-opc_iload_0)/4);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(1);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_istore_0: case opc_istore_1:
|
||
|
case opc_istore_2: case opc_istore_3:
|
||
|
case opc_fstore_0: case opc_fstore_1:
|
||
|
case opc_fstore_2: case opc_fstore_3:
|
||
|
case opc_astore_0: case opc_astore_1:
|
||
25 years ago
|
case opc_astore_2: case opc_astore_3: {
|
||
|
int slot = (opcode-opc_istore_0) & 3;
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opc_istore +
|
||
|
(opcode-opc_istore_0)/4);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(1);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_lstore_0: case opc_lstore_1:
|
||
|
case opc_lstore_2: case opc_lstore_3:
|
||
|
case opc_dstore_0: case opc_dstore_1:
|
||
25 years ago
|
case opc_dstore_2: case opc_dstore_3: {
|
||
|
int slot = (opcode-opc_istore_0) & 3;
|
||
|
if (slot >= maxLocals-1)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opc_istore
|
||
|
+ (opcode-opc_istore_0)/4);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(1);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_iload: case opc_fload: case opc_aload:
|
||
25 years ago
|
case opc_istore: case opc_fstore: case opc_astore: {
|
||
|
int slot = input.readUnsignedByte();
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opcode);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(2);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+slot);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_lstore: case opc_dstore:
|
||
25 years ago
|
case opc_lload: case opc_dload: {
|
||
|
int slot = input.readUnsignedByte();
|
||
|
if (slot >= maxLocals - 1)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opcode);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(2);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+slot);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
|
case opc_ret: {
|
||
|
int slot = input.readUnsignedByte();
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opcode);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setLength(2);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+slot);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
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_fconst_0: case opc_fconst_1: case opc_fconst_2:
|
||
25 years ago
|
instr.replaceInstruction(opc_ldc);
|
||
|
instr.setConstant
|
||
|
(constants[opcode - opc_aconst_null]);
|
||
|
instr.setLength(1);
|
||
26 years ago
|
break;
|
||
|
case opc_lconst_0: case opc_lconst_1:
|
||
26 years ago
|
case opc_dconst_0: case opc_dconst_1:
|
||
25 years ago
|
instr.replaceInstruction(opc_ldc2_w);
|
||
|
instr.setConstant
|
||
|
(constants[opcode - opc_aconst_null]);
|
||
|
instr.setLength(1);
|
||
26 years ago
|
break;
|
||
|
case opc_bipush:
|
||
25 years ago
|
instr.replaceInstruction(opc_ldc);
|
||
|
instr.setConstant(new Integer(input.readByte()));
|
||
|
instr.setLength(2);
|
||
26 years ago
|
break;
|
||
|
case opc_sipush:
|
||
25 years ago
|
instr.replaceInstruction(opc_ldc);
|
||
|
instr.setConstant(new Integer(input.readShort()));
|
||
|
instr.setLength(3);
|
||
26 years ago
|
break;
|
||
26 years ago
|
case opc_ldc: {
|
||
|
int index = input.readUnsignedByte();
|
||
|
int tag = cp.getTag(index);
|
||
|
if (tag != cp.STRING
|
||
|
&& tag != cp.INTEGER && tag != cp.FLOAT)
|
||
|
throw new ClassFormatException
|
||
|
("wrong constant tag: "+tag);
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setConstant(cp.getConstant(index));
|
||
|
instr.setLength(2);
|
||
26 years ago
|
break;
|
||
26 years ago
|
}
|
||
|
case opc_ldc_w: {
|
||
|
int index = input.readUnsignedShort();
|
||
|
int tag = cp.getTag(index);
|
||
|
if (tag != cp.STRING
|
||
|
&& tag != cp.INTEGER && tag != cp.FLOAT)
|
||
|
throw new ClassFormatException
|
||
|
("wrong constant tag: "+tag);
|
||
25 years ago
|
instr.replaceInstruction(opc_ldc);
|
||
|
instr.setConstant(cp.getConstant(index));
|
||
|
instr.setLength(3);
|
||
26 years ago
|
break;
|
||
26 years ago
|
}
|
||
|
case opc_ldc2_w: {
|
||
|
int index = input.readUnsignedShort();
|
||
|
int tag = cp.getTag(index);
|
||
|
if (tag != cp.LONG && tag != cp.DOUBLE)
|
||
|
throw new ClassFormatException
|
||
|
("wrong constant tag: "+tag);
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setConstant(cp.getConstant(index));
|
||
|
instr.setLength(3);
|
||
26 years ago
|
break;
|
||
|
}
|
||
25 years ago
|
case opc_iinc: {
|
||
|
int slot = input.readUnsignedByte();
|
||
|
if (slot >= maxLocals)
|
||
26 years ago
|
throw new ClassFormatError
|
||
25 years ago
|
("Invalid local slot "+slot);
|
||
|
instr.replaceInstruction(opcode);
|
||
|
instr.setLocalSlot(slot);
|
||
|
instr.setIntData(input.readByte());
|
||
|
instr.setLength(3);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+slot
|
||
|
+" "+instr.getIntData());
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_goto:
|
||
26 years ago
|
case opc_jsr:
|
||
26 years ago
|
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:
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setLength(3);
|
||
|
succAddrs[addr] = new int[] { addr+input.readShort() };
|
||
26 years ago
|
predcounts[succAddrs[addr][0]]++;
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.print(" "+succAddrs[addr][0]);
|
||
26 years ago
|
break;
|
||
|
|
||
|
case opc_goto_w:
|
||
|
case opc_jsr_w:
|
||
25 years ago
|
instr.replaceInstruction(opcode - (opc_goto_w - opc_goto));
|
||
|
instr.setLength(5);
|
||
|
succAddrs[addr] = new int[] { addr+input.readInt() };
|
||
26 years ago
|
predcounts[succAddrs[addr][0]]++;
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.print(" "+succAddrs[addr][0]);
|
||
26 years ago
|
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();
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setIntData(low);
|
||
26 years ago
|
succAddrs[addr] = new int[high-low+2];
|
||
|
for (int i=0; i+low <= high; i++) {
|
||
|
succAddrs[addr][i] = addr + input.readInt();
|
||
26 years ago
|
predcounts[succAddrs[addr][i]]++;
|
||
26 years ago
|
}
|
||
|
succAddrs[addr][high-low+1] = addr + def;
|
||
26 years ago
|
predcounts[addr + def]++;
|
||
25 years ago
|
instr.setLength(length + 13 + 4 * (high-low+1));
|
||
26 years ago
|
break;
|
||
|
}
|
||
|
case opc_lookupswitch: {
|
||
|
int length = 3-(addr % 4);
|
||
|
input.readFully(new byte[length]);
|
||
|
int def = input.readInt();
|
||
|
int npairs = input.readInt();
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
26 years ago
|
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();
|
||
26 years ago
|
predcounts[succAddrs[addr][i]]++;
|
||
26 years ago
|
}
|
||
|
succAddrs[addr][npairs] = addr + def;
|
||
26 years ago
|
predcounts[addr + def]++;
|
||
25 years ago
|
instr.setValues(values);
|
||
|
instr.setLength(length + 9 + 8 * npairs);
|
||
26 years ago
|
break;
|
||
|
}
|
||
25 years ago
|
|
||
26 years ago
|
case opc_getstatic:
|
||
|
case opc_getfield:
|
||
|
case opc_putstatic:
|
||
|
case opc_putfield:
|
||
|
case opc_invokespecial:
|
||
|
case opc_invokestatic:
|
||
26 years ago
|
case opc_invokevirtual: {
|
||
26 years ago
|
int index = input.readUnsignedShort();
|
||
|
int tag = cp.getTag(index);
|
||
25 years ago
|
if (opcode < opc_invokevirtual) {
|
||
26 years ago
|
if (tag != cp.FIELDREF)
|
||
|
throw new ClassFormatException
|
||
|
("field tag mismatch: "+tag);
|
||
|
} else {
|
||
|
if (tag != cp.METHODREF)
|
||
|
throw new ClassFormatException
|
||
|
("method tag mismatch: "+tag);
|
||
|
}
|
||
|
Reference ref = cp.getRef(index);
|
||
|
if (ref.getName().charAt(0) == '<'
|
||
|
&& (!ref.getName().equals("<init>")
|
||
|
|| opcode != opc_invokespecial))
|
||
|
throw new ClassFormatException
|
||
|
("Illegal call of special method/field "+ref);
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setReference(ref);
|
||
|
instr.setLength(3);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.print(" "+ref);
|
||
26 years ago
|
break;
|
||
26 years ago
|
}
|
||
|
case opc_invokeinterface: {
|
||
26 years ago
|
int index = input.readUnsignedShort();
|
||
|
int tag = cp.getTag(index);
|
||
|
if (tag != cp.INTERFACEMETHODREF)
|
||
|
throw new ClassFormatException
|
||
|
("interface tag mismatch: "+tag);
|
||
|
Reference ref = cp.getRef(index);
|
||
|
if (ref.getName().charAt(0) == '<')
|
||
|
throw new ClassFormatException
|
||
|
("Illegal call of special method "+ref);
|
||
25 years ago
|
int nargs = input.readUnsignedByte();
|
||
|
if (TypeSignature.getArgumentSize(ref.getType())
|
||
|
!= nargs - 1)
|
||
|
throw new ClassFormatException
|
||
|
("Interface nargs mismatch: "+ref+" vs. "+nargs);
|
||
|
if (input.readUnsignedByte() != 0)
|
||
|
throw new ClassFormatException
|
||
|
("Interface reserved param not zero");
|
||
|
|
||
|
instr.replaceInstruction(opcode);
|
||
|
instr.setReference(ref);
|
||
|
instr.setLength(5);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.print(" "+ref);
|
||
26 years ago
|
break;
|
||
26 years ago
|
}
|
||
26 years ago
|
|
||
|
case opc_new:
|
||
|
case opc_checkcast:
|
||
26 years ago
|
case opc_instanceof: {
|
||
|
String type = cp.getClassType(input.readUnsignedShort());
|
||
|
if (opcode == opc_new && type.charAt(0) == '[')
|
||
|
throw new ClassFormatException
|
||
|
("Can't create array with opc_new");
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setClazzType(type);
|
||
|
instr.setLength(3);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+type);
|
||
26 years ago
|
break;
|
||
26 years ago
|
}
|
||
25 years ago
|
case opc_multianewarray: {
|
||
|
String type = cp.getClassType(input.readUnsignedShort());
|
||
|
int dims = input.readUnsignedByte();
|
||
|
for (int i=0; i < dims; i++)
|
||
|
/* Note that since type is a valid type
|
||
|
* signature, there must be a non bracket
|
||
|
* character, before the string is over.
|
||
|
* So there is no StringIndexOutOfBoundsException.
|
||
|
*/
|
||
|
if (type.charAt(i) != '[')
|
||
26 years ago
|
throw new ClassFormatException
|
||
|
("multianewarray called for non array:"
|
||
|
+ instr.getDescription());
|
||
25 years ago
|
instr.replaceInstruction(opcode);
|
||
|
instr.setClazzType(type);
|
||
|
instr.setIntData(dims);
|
||
|
instr.setLength(4);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" " + type + " " + dims);
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_anewarray: {
|
||
26 years ago
|
String type = cp.getClassType(input.readUnsignedShort());
|
||
25 years ago
|
instr.replaceInstruction(opc_multianewarray);
|
||
|
instr.setClazzType(("["+type).intern());
|
||
|
instr.setIntData(1);
|
||
|
instr.setLength(3);
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+type);
|
||
26 years ago
|
break;
|
||
|
}
|
||
|
case opc_newarray: {
|
||
|
char sig = newArrayTypes.charAt
|
||
|
(input.readUnsignedByte()-4);
|
||
25 years ago
|
String type = new String (new char[] { '[', sig });
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
25 years ago
|
GlobalOptions.err.print(" "+type);
|
||
|
instr.replaceInstruction(opc_multianewarray);
|
||
|
instr.setClazzType(type);
|
||
|
instr.setIntData(1);
|
||
|
instr.setLength(2);
|
||
26 years ago
|
break;
|
||
26 years ago
|
}
|
||
26 years ago
|
|
||
25 years ago
|
case opc_nop:
|
||
|
case opc_iaload: case opc_laload: case opc_faload:
|
||
|
case opc_daload: case opc_aaload:
|
||
|
case opc_baload: case opc_caload: case opc_saload:
|
||
|
case opc_iastore: case opc_lastore: case opc_fastore:
|
||
|
case opc_dastore: case opc_aastore:
|
||
|
case opc_bastore: case opc_castore: case opc_sastore:
|
||
|
case opc_pop: case opc_pop2:
|
||
|
case opc_dup: case opc_dup_x1: case opc_dup_x2:
|
||
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
|
||
|
case opc_swap:
|
||
|
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
|
||
|
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
|
||
|
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
|
||
|
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
|
||
|
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
|
||
|
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
|
||
|
case opc_ishl: case opc_lshl:
|
||
|
case opc_ishr: case opc_lshr:
|
||
|
case opc_iushr: case opc_lushr:
|
||
|
case opc_iand: case opc_land:
|
||
|
case opc_ior: case opc_lor:
|
||
|
case opc_ixor: case opc_lxor:
|
||
|
case opc_i2l: case opc_i2f: case opc_i2d:
|
||
|
case opc_l2i: case opc_l2f: case opc_l2d:
|
||
|
case opc_f2i: case opc_f2l: case opc_f2d:
|
||
|
case opc_d2i: case opc_d2l: case opc_d2f:
|
||
|
case opc_i2b: case opc_i2c: case opc_i2s:
|
||
|
case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
|
||
|
case opc_dcmpl: case opc_dcmpg:
|
||
|
case opc_ireturn: case opc_lreturn:
|
||
|
case opc_freturn: case opc_dreturn: case opc_areturn:
|
||
|
case opc_return:
|
||
|
case opc_athrow:
|
||
|
case opc_arraylength:
|
||
|
case opc_monitorenter: case opc_monitorexit:
|
||
|
instr.replaceInstruction(opcode);
|
||
|
instr.setLength(1);
|
||
|
break;
|
||
26 years ago
|
default:
|
||
25 years ago
|
throw new ClassFormatError("Invalid opcode "+opcode);
|
||
26 years ago
|
}
|
||
26 years ago
|
if ((GlobalOptions.debuggingFlags
|
||
|
& GlobalOptions.DEBUG_BYTECODE) != 0)
|
||
|
GlobalOptions.err.println();
|
||
25 years ago
|
addr += instr.getLength();
|
||
26 years ago
|
}
|
||
|
}
|
||
|
for (Instruction instr = firstInstr;
|
||
25 years ago
|
instr != null; instr = instr.getNextByAddr()) {
|
||
|
int addr = instr.getAddr();
|
||
26 years ago
|
if (succAddrs[addr] != null) {
|
||
|
int length = succAddrs[addr].length;
|
||
|
instr.succs = new Instruction[length];
|
||
|
for (int i=0; i < length; i++) {
|
||
26 years ago
|
int succAddr = succAddrs[addr][i];
|
||
|
instr.succs[i] = instrs[succAddr];
|
||
|
if (instr.succs[i].preds == null)
|
||
|
instr.succs[i].preds
|
||
|
= new Instruction[predcounts[succAddr]];
|
||
|
instr.succs[i].preds[--predcounts[succAddr]] = instr;
|
||
26 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
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
|
||
25 years ago
|
= instrs[input.readUnsignedShort()].getPrevByAddr();
|
||
26 years ago
|
exceptionHandlers[i].catcher
|
||
|
= instrs[input.readUnsignedShort()];
|
||
|
int index = input.readUnsignedShort();
|
||
|
exceptionHandlers[i].type = (index == 0) ? null
|
||
25 years ago
|
: cp.getClassName(index);
|
||
26 years ago
|
}
|
||
|
}
|
||
|
readAttributes(cp, input, FULLINFO);
|
||
|
}
|
||
|
|
||
25 years ago
|
public void dumpCode(java.io.PrintWriter output) {
|
||
26 years ago
|
for (Instruction instr = firstInstr;
|
||
25 years ago
|
instr != null; instr = instr.getNextByAddr()) {
|
||
26 years ago
|
output.println(instr.getDescription() + " "
|
||
|
+ Integer.toHexString(hashCode()));
|
||
26 years ago
|
if (instr.succs != null) {
|
||
|
output.print("\tsuccs: "+instr.succs[0]);
|
||
|
for (int i = 1; i < instr.succs.length; i++)
|
||
|
output.print(", "+instr.succs[i]);
|
||
|
output.println();
|
||
|
}
|
||
26 years ago
|
if (instr.preds != null) {
|
||
|
output.print("\tpreds: " + instr.preds[0]);
|
||
|
for (int i=1; i < instr.preds.length; i++)
|
||
|
output.print(", " + instr.preds[i]);
|
||
26 years ago
|
output.println();
|
||
|
}
|
||
|
}
|
||
26 years ago
|
for (int i=0; i< exceptionHandlers.length; i++) {
|
||
|
output.println("catch " + exceptionHandlers[i].type
|
||
|
+ " from " + exceptionHandlers[i].start
|
||
|
+ " to " + exceptionHandlers[i].end
|
||
|
+ " catcher " + exceptionHandlers[i].catcher);
|
||
|
}
|
||
26 years ago
|
}
|
||
26 years ago
|
|
||
26 years ago
|
public void reserveSmallConstants(GrowableConstantPool gcp) {
|
||
|
next_instr:
|
||
|
for (Instruction instr = firstInstr;
|
||
25 years ago
|
instr != null; instr = instr.getNextByAddr()) {
|
||
|
if (instr.getOpcode() == opc_ldc) {
|
||
|
Object constant = instr.getConstant();
|
||
|
if (constant == null)
|
||
26 years ago
|
continue next_instr;
|
||
|
for (int i=1; i < constants.length; i++) {
|
||
25 years ago
|
if (constant.equals(constants[i]))
|
||
26 years ago
|
continue next_instr;
|
||
|
}
|
||
25 years ago
|
if (constant instanceof Integer) {
|
||
|
int value = ((Integer) constant).intValue();
|
||
26 years ago
|
if (value >= Short.MIN_VALUE
|
||
|
&& value <= Short.MAX_VALUE)
|
||
|
continue next_instr;
|
||
|
}
|
||
25 years ago
|
gcp.reserveConstant(constant);
|
||
26 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
26 years ago
|
public void prepareWriting(GrowableConstantPool gcp) {
|
||
25 years ago
|
/* Recalculate addr, length and add all constants to gcp */
|
||
26 years ago
|
int addr = 0;
|
||
|
for (Instruction instr = firstInstr;
|
||
25 years ago
|
instr != null; instr = instr.getNextByAddr()) {
|
||
|
int opcode = instr.getOpcode();
|
||
|
instr.setAddr(addr);
|
||
|
int length;
|
||
|
switch_opc:
|
||
|
switch (opcode) {
|
||
|
case opc_ldc:
|
||
|
case opc_ldc2_w: {
|
||
|
Object constant = instr.getConstant();
|
||
|
if (constant == null) {
|
||
|
length = 1;
|
||
|
break switch_opc;
|
||
26 years ago
|
}
|
||
|
for (int i=1; i < constants.length; i++) {
|
||
25 years ago
|
if (constant.equals(constants[i])) {
|
||
|
length = 1;
|
||
|
break switch_opc;
|
||
26 years ago
|
}
|
||
|
}
|
||
25 years ago
|
if (opcode == opc_ldc2_w) {
|
||
|
gcp.putLongConstant(constant);
|
||
|
length = 3;
|
||
|
break switch_opc;
|
||
26 years ago
|
}
|
||
25 years ago
|
if (constant instanceof Integer) {
|
||
|
int value = ((Integer) constant).intValue();
|
||
26 years ago
|
if (value >= Byte.MIN_VALUE
|
||
26 years ago
|
&& value <= Byte.MAX_VALUE) {
|
||
25 years ago
|
length = 2;
|
||
|
break switch_opc;
|
||
26 years ago
|
} else if (value >= Short.MIN_VALUE
|
||
26 years ago
|
&& value <= Short.MAX_VALUE) {
|
||
25 years ago
|
length = 3;
|
||
|
break switch_opc;
|
||
26 years ago
|
}
|
||
|
}
|
||
25 years ago
|
if (gcp.putConstant(constant) < 256) {
|
||
|
length = 2;
|
||
26 years ago
|
} else {
|
||
25 years ago
|
length = 3;
|
||
26 years ago
|
}
|
||
25 years ago
|
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:
|
||
|
case opc_ret:
|
||
|
case opc_iinc: {
|
||
|
int slot = instr.getLocalSlot();
|
||
|
if (opcode == opc_iinc) {
|
||
|
if (slot < 256
|
||
|
&& instr.getIntData() >= Byte.MIN_VALUE
|
||
|
&& instr.getIntData() <= Byte.MAX_VALUE)
|
||
|
length = 3;
|
||
26 years ago
|
else
|
||
25 years ago
|
length = 6;
|
||
26 years ago
|
} else {
|
||
25 years ago
|
if (opcode != opc_ret && slot < 4)
|
||
|
length = 1;
|
||
|
else if (slot < 256)
|
||
|
length = 2;
|
||
26 years ago
|
else
|
||
25 years ago
|
length = 4;
|
||
26 years ago
|
}
|
||
25 years ago
|
break;
|
||
|
}
|
||
|
case opc_tableswitch: {
|
||
|
length = 3-(addr % 4);
|
||
|
length += 9 + 4 * instr.succs.length;
|
||
|
break;
|
||
|
}
|
||
|
case opc_lookupswitch: {
|
||
|
length = 3-(addr % 4);
|
||
|
length += 1 + 8 * instr.succs.length;
|
||
|
break;
|
||
|
}
|
||
|
case opc_goto: case opc_jsr: {
|
||
|
int dist = instr.succs[0].getAddr() - instr.getAddr();
|
||
26 years ago
|
if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) {
|
||
25 years ago
|
/* wide goto / jsr */
|
||
|
length = 5;
|
||
|
break;
|
||
|
}
|
||
|
/* 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:
|
||
|
length = 3;
|
||
|
break;
|
||
|
case opc_multianewarray: {
|
||
|
if (instr.getIntData() == 1) {
|
||
|
String clazz = instr.getClazzType().substring(1);
|
||
|
if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) {
|
||
|
length = 2;
|
||
26 years ago
|
} else {
|
||
|
gcp.putClassType(clazz);
|
||
25 years ago
|
length = 3;
|
||
26 years ago
|
}
|
||
26 years ago
|
} else {
|
||
25 years ago
|
gcp.putClassType(instr.getClazzType());
|
||
|
length = 4;
|
||
26 years ago
|
}
|
||
25 years ago
|
break;
|
||
|
}
|
||
|
case opc_getstatic:
|
||
|
case opc_getfield:
|
||
|
case opc_putstatic:
|
||
|
case opc_putfield:
|
||
|
gcp.putRef(gcp.FIELDREF, instr.getReference());
|
||
|
length = 3;
|
||
|
break;
|
||
|
case opc_invokespecial:
|
||
|
case opc_invokestatic:
|
||
|
case opc_invokevirtual:
|
||
|
gcp.putRef(gcp.METHODREF, instr.getReference());
|
||
|
length = 3;
|
||
|
break;
|
||
|
case opc_invokeinterface:
|
||
|
gcp.putRef(gcp.INTERFACEMETHODREF, instr.getReference());
|
||
|
length = 5;
|
||
|
break;
|
||
|
case opc_new:
|
||
|
case opc_checkcast:
|
||
|
case opc_instanceof:
|
||
|
gcp.putClassType(instr.getClazzType());
|
||
|
length = 3;
|
||
|
break;
|
||
|
case opc_nop:
|
||
|
case opc_iaload: case opc_laload: case opc_faload:
|
||
|
case opc_daload: case opc_aaload:
|
||
|
case opc_baload: case opc_caload: case opc_saload:
|
||
|
case opc_iastore: case opc_lastore: case opc_fastore:
|
||
|
case opc_dastore: case opc_aastore:
|
||
|
case opc_bastore: case opc_castore: case opc_sastore:
|
||
|
case opc_pop: case opc_pop2:
|
||
|
case opc_dup: case opc_dup_x1: case opc_dup_x2:
|
||
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
|
||
|
case opc_swap:
|
||
|
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
|
||
|
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
|
||
|
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
|
||
|
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
|
||
|
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
|
||
|
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
|
||
|
case opc_ishl: case opc_lshl:
|
||
|
case opc_ishr: case opc_lshr:
|
||
|
case opc_iushr: case opc_lushr:
|
||
|
case opc_iand: case opc_land:
|
||
|
case opc_ior: case opc_lor:
|
||
|
case opc_ixor: case opc_lxor:
|
||
|
case opc_i2l: case opc_i2f: case opc_i2d:
|
||
|
case opc_l2i: case opc_l2f: case opc_l2d:
|
||
|
case opc_f2i: case opc_f2l: case opc_f2d:
|
||
|
case opc_d2i: case opc_d2l: case opc_d2f:
|
||
|
case opc_i2b: case opc_i2c: case opc_i2s:
|
||
|
case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
|
||
|
case opc_dcmpl: case opc_dcmpg:
|
||
|
case opc_ireturn: case opc_lreturn:
|
||
|
case opc_freturn: case opc_dreturn: case opc_areturn:
|
||
|
case opc_return:
|
||
|
case opc_athrow:
|
||
|
case opc_arraylength:
|
||
|
case opc_monitorenter: case opc_monitorexit:
|
||
|
length = 1;
|
||
|
break;
|
||
|
default:
|
||
|
throw new ClassFormatError("Invalid opcode "+opcode);
|
||
26 years ago
|
}
|
||
25 years ago
|
instr.setLength(length);
|
||
|
addr += length;
|
||
26 years ago
|
}
|
||
26 years ago
|
codeLength = addr;
|
||
26 years ago
|
for (int i=0; i< exceptionHandlers.length; i++)
|
||
|
if (exceptionHandlers[i].type != null)
|
||
|
gcp.putClassName(exceptionHandlers[i].type);
|
||
|
if (lvt != null) {
|
||
|
gcp.putUTF8("LocalVariableTable");
|
||
|
for (int i=0; i < lvt.length; i++) {
|
||
|
gcp.putUTF8(lvt[i].name);
|
||
|
gcp.putUTF8(lvt[i].type);
|
||
|
}
|
||
|
}
|
||
|
if (lnt != null)
|
||
|
gcp.putUTF8("LineNumberTable");
|
||
|
prepareAttributes(gcp);
|
||
|
}
|
||
|
|
||
|
protected int getKnownAttributeCount() {
|
||
|
int count = 0;
|
||
|
if (lvt != null)
|
||
|
count++;
|
||
|
if (lnt != null)
|
||
|
count++;
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
public void writeKnownAttributes(GrowableConstantPool gcp,
|
||
|
DataOutputStream output)
|
||
|
throws IOException {
|
||
|
if (lvt != null) {
|
||
|
output.writeShort(gcp.putUTF8("LocalVariableTable"));
|
||
|
int count = lvt.length;
|
||
|
int length = 2 + 10 * count;
|
||
|
output.writeInt(length);
|
||
|
output.writeShort(count);
|
||
|
for (int i=0; i < count; i++) {
|
||
25 years ago
|
output.writeShort(lvt[i].start.getAddr());
|
||
|
output.writeShort(lvt[i].end.getAddr() + lvt[i].end.getLength()
|
||
|
- lvt[i].start.getAddr());
|
||
26 years ago
|
output.writeShort(gcp.putUTF8(lvt[i].name));
|
||
|
output.writeShort(gcp.putUTF8(lvt[i].type));
|
||
|
output.writeShort(lvt[i].slot);
|
||
|
}
|
||
|
}
|
||
|
if (lnt != null) {
|
||
|
output.writeShort(gcp.putUTF8("LineNumberTable"));
|
||
|
int count = lnt.length;
|
||
|
int length = 2 + 4 * count;
|
||
|
output.writeInt(length);
|
||
|
output.writeShort(count);
|
||
|
for (int i=0; i < count; i++) {
|
||
25 years ago
|
output.writeShort(lnt[i].start.getAddr());
|
||
26 years ago
|
output.writeShort(lnt[i].linenr);
|
||
|
}
|
||
|
}
|
||
26 years ago
|
}
|
||
26 years ago
|
|
||
26 years ago
|
public void write(GrowableConstantPool gcp,
|
||
|
DataOutputStream output) throws IOException {
|
||
26 years ago
|
output.writeShort(maxStack);
|
||
|
output.writeShort(maxLocals);
|
||
26 years ago
|
output.writeInt(codeLength);
|
||
26 years ago
|
for (Instruction instr = firstInstr;
|
||
25 years ago
|
instr != null; instr = instr.getNextByAddr()) {
|
||
|
int opcode = instr.getOpcode();
|
||
26 years ago
|
switch_opc:
|
||
25 years ago
|
switch (opcode) {
|
||
26 years ago
|
case opc_iload: case opc_lload:
|
||
|
case opc_fload: case opc_dload: case opc_aload:
|
||
|
case opc_istore: case opc_lstore:
|
||
25 years ago
|
case opc_fstore: case opc_dstore: case opc_astore: {
|
||
|
int slot = instr.getLocalSlot();
|
||
|
if (slot < 4) {
|
||
|
if (opcode < opc_istore)
|
||
26 years ago
|
output.writeByte(opc_iload_0
|
||
25 years ago
|
+ 4*(opcode-opc_iload)
|
||
|
+ slot);
|
||
26 years ago
|
else
|
||
|
output.writeByte(opc_istore_0
|
||
25 years ago
|
+ 4*(opcode-opc_istore)
|
||
|
+ slot);
|
||
|
} else if (slot < 256) {
|
||
|
output.writeByte(opcode);
|
||
|
output.writeByte(slot);
|
||
26 years ago
|
} else {
|
||
|
output.writeByte(opc_wide);
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
output.writeShort(slot);
|
||
26 years ago
|
}
|
||
|
break;
|
||
25 years ago
|
}
|
||
|
case opc_ret: {
|
||
|
int slot = instr.getLocalSlot();
|
||
|
if (slot < 256) {
|
||
|
output.writeByte(opcode);
|
||
|
output.writeByte(slot);
|
||
26 years ago
|
} else {
|
||
|
output.writeByte(opc_wide);
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
output.writeShort(slot);
|
||
26 years ago
|
}
|
||
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_ldc:
|
||
25 years ago
|
case opc_ldc2_w: {
|
||
|
Object constant = instr.getConstant();
|
||
|
if (constant == null) {
|
||
26 years ago
|
output.writeByte(opc_aconst_null);
|
||
|
break switch_opc;
|
||
|
}
|
||
|
for (int i=1; i < constants.length; i++) {
|
||
25 years ago
|
if (constant.equals(constants[i])) {
|
||
26 years ago
|
output.writeByte(opc_aconst_null + i);
|
||
|
break switch_opc;
|
||
|
}
|
||
|
}
|
||
25 years ago
|
if (opcode == opc_ldc2_w) {
|
||
|
output.writeByte(opcode);
|
||
|
output.writeShort(gcp.putLongConstant(constant));
|
||
26 years ago
|
} else {
|
||
25 years ago
|
if (constant instanceof Integer) {
|
||
|
int value = ((Integer) constant).intValue();
|
||
26 years ago
|
if (value >= Byte.MIN_VALUE
|
||
26 years ago
|
&& value <= Byte.MAX_VALUE) {
|
||
|
|
||
26 years ago
|
output.writeByte(opc_bipush);
|
||
25 years ago
|
output.writeByte(((Integer)constant)
|
||
26 years ago
|
.intValue());
|
||
26 years ago
|
break switch_opc;
|
||
|
} else if (value >= Short.MIN_VALUE
|
||
26 years ago
|
&& value <= Short.MAX_VALUE) {
|
||
26 years ago
|
output.writeByte(opc_sipush);
|
||
25 years ago
|
output.writeShort(((Integer)constant)
|
||
26 years ago
|
.intValue());
|
||
26 years ago
|
break switch_opc;
|
||
26 years ago
|
}
|
||
|
}
|
||
25 years ago
|
if (instr.getLength() == 2) {
|
||
26 years ago
|
output.writeByte(opc_ldc);
|
||
25 years ago
|
output.writeByte(gcp.putConstant(constant));
|
||
26 years ago
|
} else {
|
||
|
output.writeByte(opc_ldc_w);
|
||
25 years ago
|
output.writeShort(gcp.putConstant(constant));
|
||
26 years ago
|
}
|
||
|
}
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
|
case opc_iinc: {
|
||
|
int slot = instr.getLocalSlot();
|
||
|
int incr = instr.getIntData();
|
||
|
if (instr.getLength() == 3) {
|
||
|
output.writeByte(opcode);
|
||
|
output.writeByte(slot);
|
||
|
output.writeByte(incr);
|
||
26 years ago
|
} else {
|
||
|
output.writeByte(opc_wide);
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
output.writeShort(slot);
|
||
|
output.writeShort(incr);
|
||
26 years ago
|
}
|
||
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_goto:
|
||
25 years ago
|
case opc_jsr:
|
||
|
if (instr.getLength() == 5) {
|
||
|
/* wide goto or jsr */
|
||
|
output.writeByte(opcode + (opc_goto_w - opc_goto));
|
||
|
output.writeInt(instr.succs[0].getAddr()
|
||
|
- instr.getAddr());
|
||
|
break;
|
||
|
}
|
||
|
/* fall through */
|
||
26 years ago
|
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:
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
output.writeShort(instr.succs[0].getAddr()
|
||
|
- instr.getAddr());
|
||
26 years ago
|
break;
|
||
|
|
||
|
case opc_tableswitch: {
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
int align = 3-(instr.getAddr() % 4);
|
||
26 years ago
|
int numcases = instr.succs.length - 1;
|
||
|
output.write(new byte[align]);
|
||
|
/* def */
|
||
25 years ago
|
output.writeInt(instr.succs[numcases].getAddr() - instr.getAddr());
|
||
26 years ago
|
/* low */
|
||
25 years ago
|
output.writeInt(instr.getIntData());
|
||
26 years ago
|
/* high */
|
||
25 years ago
|
output.writeInt(instr.getIntData() + numcases - 1);
|
||
26 years ago
|
for (int i=0; i < numcases; i++)
|
||
25 years ago
|
output.writeInt(instr.succs[i].getAddr() - instr.getAddr());
|
||
26 years ago
|
break;
|
||
|
}
|
||
|
case opc_lookupswitch: {
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
int[] values = instr.getValues();
|
||
|
int align = 3-(instr.getAddr() % 4);
|
||
26 years ago
|
int numcases = values.length;
|
||
|
output.write(new byte[align]);
|
||
|
/* def */
|
||
25 years ago
|
output.writeInt(instr.succs[numcases].getAddr() - instr.getAddr());
|
||
26 years ago
|
output.writeInt(numcases);
|
||
|
for (int i=0; i < numcases; i++) {
|
||
|
output.writeInt(values[i]);
|
||
25 years ago
|
output.writeInt(instr.succs[i].getAddr() - instr.getAddr());
|
||
26 years ago
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case opc_getstatic:
|
||
|
case opc_getfield:
|
||
|
case opc_putstatic:
|
||
|
case opc_putfield:
|
||
25 years ago
|
output.writeByte(opcode);
|
||
26 years ago
|
output.writeShort(gcp.putRef(gcp.FIELDREF,
|
||
25 years ago
|
instr.getReference()));
|
||
26 years ago
|
break;
|
||
|
|
||
|
case opc_invokespecial:
|
||
|
case opc_invokestatic:
|
||
|
case opc_invokeinterface:
|
||
25 years ago
|
case opc_invokevirtual: {
|
||
|
Reference ref = instr.getReference();
|
||
|
output.writeByte(opcode);
|
||
|
if (opcode == opc_invokeinterface) {
|
||
|
output.writeShort(gcp.putRef(gcp.INTERFACEMETHODREF, ref));
|
||
|
output.writeByte
|
||
|
(TypeSignature.getArgumentSize(ref.getType()) + 1);
|
||
26 years ago
|
output.writeByte(0);
|
||
26 years ago
|
} else
|
||
25 years ago
|
output.writeShort(gcp.putRef(gcp.METHODREF, ref));
|
||
26 years ago
|
break;
|
||
25 years ago
|
}
|
||
26 years ago
|
case opc_new:
|
||
|
case opc_checkcast:
|
||
|
case opc_instanceof:
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
output.writeShort(gcp.putClassType(instr.getClazzType()));
|
||
26 years ago
|
break;
|
||
26 years ago
|
case opc_multianewarray:
|
||
25 years ago
|
if (instr.getIntData() == 1) {
|
||
|
String clazz = instr.getClazzType().substring(1);
|
||
26 years ago
|
int index = newArrayTypes.indexOf(clazz.charAt(0));
|
||
|
if (index != -1) {
|
||
|
output.writeByte(opc_newarray);
|
||
|
output.writeByte(index + 4);
|
||
|
} else {
|
||
|
output.writeByte(opc_anewarray);
|
||
26 years ago
|
output.writeShort(gcp.putClassType(clazz));
|
||
26 years ago
|
}
|
||
|
} else {
|
||
25 years ago
|
output.writeByte(opcode);
|
||
|
output.writeShort(gcp.putClassType(instr.getClazzType()));
|
||
|
output.writeByte(instr.getIntData());
|
||
26 years ago
|
}
|
||
26 years ago
|
break;
|
||
|
|
||
25 years ago
|
case opc_nop:
|
||
|
case opc_iaload: case opc_laload: case opc_faload:
|
||
|
case opc_daload: case opc_aaload:
|
||
|
case opc_baload: case opc_caload: case opc_saload:
|
||
|
case opc_iastore: case opc_lastore: case opc_fastore:
|
||
|
case opc_dastore: case opc_aastore:
|
||
|
case opc_bastore: case opc_castore: case opc_sastore:
|
||
|
case opc_pop: case opc_pop2:
|
||
|
case opc_dup: case opc_dup_x1: case opc_dup_x2:
|
||
|
case opc_dup2: case opc_dup2_x1: case opc_dup2_x2:
|
||
|
case opc_swap:
|
||
|
case opc_iadd: case opc_ladd: case opc_fadd: case opc_dadd:
|
||
|
case opc_isub: case opc_lsub: case opc_fsub: case opc_dsub:
|
||
|
case opc_imul: case opc_lmul: case opc_fmul: case opc_dmul:
|
||
|
case opc_idiv: case opc_ldiv: case opc_fdiv: case opc_ddiv:
|
||
|
case opc_irem: case opc_lrem: case opc_frem: case opc_drem:
|
||
|
case opc_ineg: case opc_lneg: case opc_fneg: case opc_dneg:
|
||
|
case opc_ishl: case opc_lshl:
|
||
|
case opc_ishr: case opc_lshr:
|
||
|
case opc_iushr: case opc_lushr:
|
||
|
case opc_iand: case opc_land:
|
||
|
case opc_ior: case opc_lor:
|
||
|
case opc_ixor: case opc_lxor:
|
||
|
case opc_i2l: case opc_i2f: case opc_i2d:
|
||
|
case opc_l2i: case opc_l2f: case opc_l2d:
|
||
|
case opc_f2i: case opc_f2l: case opc_f2d:
|
||
|
case opc_d2i: case opc_d2l: case opc_d2f:
|
||
|
case opc_i2b: case opc_i2c: case opc_i2s:
|
||
|
case opc_lcmp: case opc_fcmpl: case opc_fcmpg:
|
||
|
case opc_dcmpl: case opc_dcmpg:
|
||
|
case opc_ireturn: case opc_lreturn:
|
||
|
case opc_freturn: case opc_dreturn: case opc_areturn:
|
||
|
case opc_return:
|
||
|
case opc_athrow:
|
||
|
case opc_arraylength:
|
||
|
case opc_monitorenter: case opc_monitorexit:
|
||
|
output.writeByte(opcode);
|
||
|
break;
|
||
26 years ago
|
default:
|
||
25 years ago
|
throw new ClassFormatError("Invalid opcode "+opcode);
|
||
26 years ago
|
}
|
||
|
}
|
||
|
|
||
|
output.writeShort(exceptionHandlers.length);
|
||
|
for (int i=0; i< exceptionHandlers.length; i++) {
|
||
25 years ago
|
output.writeShort(exceptionHandlers[i].start.getAddr());
|
||
|
output.writeShort(exceptionHandlers[i].end.getNextByAddr().getAddr());
|
||
|
output.writeShort(exceptionHandlers[i].catcher.getAddr());
|
||
26 years ago
|
output.writeShort((exceptionHandlers[i].type == null) ? 0
|
||
26 years ago
|
: gcp.putClassName(exceptionHandlers[i].type));
|
||
26 years ago
|
}
|
||
26 years ago
|
writeAttributes(gcp, output);
|
||
|
}
|
||
|
|
||
|
public int getSize() {
|
||
|
/* maxStack: 2
|
||
|
* maxLocals: 2
|
||
|
* code: 4 + codeLength
|
||
|
* exc count: 2
|
||
|
* exceptions: n * 8
|
||
|
* attributes:
|
||
|
* lvt_name: 2
|
||
|
* lvt_length: 4
|
||
|
* lvt_count: 2
|
||
|
* lvt_entries: n * 10
|
||
|
* attributes:
|
||
|
* lnt_name: 2
|
||
|
* lnt_length: 4
|
||
|
* lnt_count: 2
|
||
|
* lnt_entries: n * 4
|
||
|
*/
|
||
|
int size = 0;
|
||
|
if (lvt != null)
|
||
|
size += 8 + lvt.length * 10;
|
||
|
if (lnt != null)
|
||
|
size += 8 + lnt.length * 4;
|
||
|
return 10 + codeLength + exceptionHandlers.length * 8
|
||
|
+ getAttributeSize() + size;
|
||
26 years ago
|
}
|
||
|
|
||
|
public int getMaxStack() {
|
||
|
return maxStack;
|
||
|
}
|
||
|
|
||
|
public int getMaxLocals() {
|
||
|
return maxLocals;
|
||
|
}
|
||
|
|
||
25 years ago
|
public MethodInfo getMethodInfo() {
|
||
|
return methodInfo;
|
||
|
}
|
||
|
|
||
25 years ago
|
public Collection getInstructions() {
|
||
|
return new AbstractCollection() {
|
||
|
public int size() {
|
||
|
return instructionCount;
|
||
|
}
|
||
|
|
||
|
public Iterator iterator() {
|
||
|
return new Iterator() {
|
||
|
Instruction instr = firstInstr;
|
||
|
|
||
|
public boolean hasNext() {
|
||
|
return instr != null;
|
||
|
}
|
||
|
|
||
|
public Object next() {
|
||
|
if (instr == null)
|
||
|
throw new NoSuchElementException();
|
||
|
Instruction result = instr;
|
||
|
instr = instr.getNextByAddr();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public void remove() {
|
||
|
instr.getPrevByAddr().removeInstruction();
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
26 years ago
|
public Instruction getFirstInstr() {
|
||
|
return firstInstr;
|
||
|
}
|
||
|
|
||
|
public Handler[] getExceptionHandlers() {
|
||
|
return exceptionHandlers;
|
||
|
}
|
||
|
|
||
26 years ago
|
public LocalVariableInfo[] getLocalVariableTable() {
|
||
|
return lvt;
|
||
|
}
|
||
|
|
||
|
public LineNumber[] getLineNumberTable() {
|
||
|
return lnt;
|
||
|
}
|
||
|
|
||
|
public void setMaxStack(int ms) {
|
||
|
maxStack = ms;
|
||
|
}
|
||
|
|
||
|
public void setMaxLocals(int ml) {
|
||
|
maxLocals = ml;
|
||
|
}
|
||
|
|
||
26 years ago
|
public void setExceptionHandlers(Handler[] handlers) {
|
||
|
exceptionHandlers = handlers;
|
||
|
}
|
||
26 years ago
|
|
||
|
public void setLocalVariableTable(LocalVariableInfo[] newLvt) {
|
||
|
lvt = newLvt;
|
||
|
}
|
||
|
|
||
|
public void setLineNumberTable(LineNumber[] newLnt) {
|
||
|
lnt = newLnt;
|
||
|
}
|
||
25 years ago
|
|
||
|
public String toString() {
|
||
|
return "Bytecode "+methodInfo;
|
||
|
}
|
||
26 years ago
|
}
|