0001: /* BytecodeInfo Copyright (C) 1999-2002 Jochen Hoenicke.
0002: *
0003: * This program is free software; you can redistribute it and/or modify
0004: * it under the terms of the GNU Lesser General Public License as published by
0005: * the Free Software Foundation; either version 2, or (at your option)
0006: * any later version.
0007: *
0008: * This program is distributed in the hope that it will be useful,
0009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0011: * GNU General Public License for more details.
0012: *
0013: * You should have received a copy of the GNU Lesser General Public License
0014: * along with this program; see the file COPYING.LESSER. If not, write to
0015: * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
0016: *
0017: * $Id: BytecodeInfo.java.in,v 4.9.2.8 2002/06/11 08:40:31 hoenicke Exp $
0018: */
0019:
0020: package jode.bytecode;
0021:
0022: import jode.GlobalOptions;
0023: import java.io.DataInputStream;
0024: import java.io.DataOutputStream;
0025: import java.io.ByteArrayInputStream;
0026: import java.io.InputStream;
0027: import java.io.EOFException;
0028: import java.io.IOException;
0029: import java.util.BitSet;
0030: import java.util.Stack;
0031: import java.util.Vector;
0032: import java.util.Enumeration;
0033: import java.util.NoSuchElementException;
0034:
0035: import java.util.List;
0036: import java.util.AbstractSequentialList;
0037: import java.util.Iterator;
0038: import java.util.ListIterator;
0039:
0040: /**
0041: * This class represents the byte code of a method. Each instruction is
0042: * stored in an Instruction instance.
0043: *
0044: * We canonicalize some opcodes: wide opcodes are mapped to short ones,
0045: * opcodes that load a constant are mapped to opc_ldc or opc_ldc2_w, and
0046: * opc_xload_x / opc_xstore_x opcodes are mapped to opc_xload / opc_xstore.
0047: */
0048: public class BytecodeInfo extends BinaryInfo implements Opcodes {
0049:
0050: private MethodInfo methodInfo;
0051: private int maxStack, maxLocals;
0052: private Handler[] exceptionHandlers;
0053: private LocalVariableInfo[] lvt;
0054: private LineNumber[] lnt;
0055:
0056: /**
0057: * A array of instructions, indexed by address. This array is only
0058: * valid while reading the code.
0059: */
0060: private Instruction[] instrs;
0061:
0062: private InstructionList instructions;
0063:
0064: private class InstructionList extends AbstractSequentialList {
0065: Instruction borderInstr;
0066: int instructionCount = 0;
0067:
0068: InstructionList() {
0069: // opc_impdep1 is used as border instruction, it may not
0070: // occur in bytecode.
0071: borderInstr = new Instruction(opc_impdep1);
0072: borderInstr.nextByAddr = borderInstr.prevByAddr = borderInstr;
0073: }
0074:
0075: public int size() {
0076: return instructionCount;
0077: }
0078:
0079: Instruction get0(int index) {
0080: Instruction instr = borderInstr;
0081: if (index < instructionCount / 2) {
0082: for (int i = 0; i <= index; i++)
0083: instr = instr.nextByAddr;
0084: } else {
0085: for (int i = instructionCount; i > index; i--)
0086: instr = instr.prevByAddr;
0087: }
0088: return instr;
0089: }
0090:
0091: public Object get(int index) {
0092: if (index < 0 || index >= instructionCount)
0093: throw new IllegalArgumentException();
0094: return get0(index);
0095: }
0096:
0097: public boolean add(Object o) {
0098: /* optimize add, since it is called many times by read() */
0099: instructionCount++;
0100: borderInstr.prevByAddr.appendInstruction((Instruction) o,
0101: BytecodeInfo.this );
0102: return true;
0103: }
0104:
0105: public ListIterator listIterator(final int startIndex) {
0106: if (startIndex < 0 || startIndex > instructionCount)
0107: throw new IllegalArgumentException();
0108: return new ListIterator() {
0109: Instruction instr = get0(startIndex);
0110: Instruction toRemove = null;
0111: int index = startIndex;
0112:
0113: public boolean hasNext() {
0114: return index < instructionCount;
0115: }
0116:
0117: public boolean hasPrevious() {
0118: return index > 0;
0119: }
0120:
0121: public Object next() {
0122: if (index >= instructionCount)
0123: throw new NoSuchElementException();
0124: index++;
0125: toRemove = instr;
0126: instr = instr.nextByAddr;
0127: // System.err.println("next: "+toRemove.getDescription());
0128: return toRemove;
0129: }
0130:
0131: public Object previous() {
0132: if (index == 0)
0133: throw new NoSuchElementException();
0134: index--;
0135: instr = instr.prevByAddr;
0136: toRemove = instr;
0137: // System.err.println("prev: "+toRemove.getDescription());
0138: return toRemove;
0139: }
0140:
0141: public int nextIndex() {
0142: return index;
0143: }
0144:
0145: public int previousIndex() {
0146: return index - 1;
0147: }
0148:
0149: public void remove() {
0150: if (toRemove == null)
0151: throw new IllegalStateException();
0152: // System.err.println("remove: "+toRemove.getDescription());
0153: instructionCount--;
0154: if (instr == toRemove)
0155: instr = instr.nextByAddr;
0156: else
0157: index--;
0158: toRemove.removeInstruction(BytecodeInfo.this );
0159: toRemove = null;
0160: }
0161:
0162: public void add(Object o) {
0163: instructionCount++;
0164: index++;
0165: // System.err.println("add: "
0166: // +((Instruction)o).getDescription()
0167: // +" after "+instr.prevByAddr
0168: // .getDescription());
0169: instr.prevByAddr.appendInstruction((Instruction) o,
0170: BytecodeInfo.this );
0171: toRemove = null;
0172: }
0173:
0174: public void set(Object o) {
0175: if (toRemove == null)
0176: throw new IllegalStateException();
0177: // System.err.println("replace "+toRemove.getDescription()
0178: // +" with "
0179: // +((Instruction)o).getDescription());
0180: toRemove.replaceInstruction((Instruction) o,
0181: BytecodeInfo.this );
0182: if (instr == toRemove)
0183: instr = (Instruction) o;
0184: toRemove = (Instruction) o;
0185: }
0186: };
0187: }
0188:
0189: void setLastAddr(int addr) {
0190: borderInstr.setAddr(addr);
0191: }
0192:
0193: int getCodeLength() {
0194: return borderInstr.getAddr();
0195: }
0196: }
0197:
0198: public BytecodeInfo(MethodInfo mi) {
0199: methodInfo = mi;
0200: }
0201:
0202: private final static Object[] constants = { null, new Integer(-1),
0203: new Integer(0), new Integer(1), new Integer(2),
0204: new Integer(3), new Integer(4), new Integer(5),
0205: new Long(0), new Long(1), new Float(0), new Float(1),
0206: new Float(2), new Double(0), new Double(1) };
0207:
0208: protected void readAttribute(String name, int length,
0209: ConstantPool cp, DataInputStream input, int howMuch)
0210: throws IOException {
0211: if ((howMuch & KNOWNATTRIBS) != 0
0212: && name.equals("LocalVariableTable")) {
0213: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
0214: GlobalOptions.err.println("LocalVariableTable of "
0215: + methodInfo);
0216: int count = input.readUnsignedShort();
0217: if (length != 2 + count * 10) {
0218: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
0219: GlobalOptions.err
0220: .println("Illegal LVT length, ignoring it");
0221: return;
0222: }
0223: lvt = new LocalVariableInfo[count];
0224: for (int i = 0; i < count; i++) {
0225: lvt[i] = new LocalVariableInfo();
0226: int start = input.readUnsignedShort();
0227: int end = start + input.readUnsignedShort();
0228: int nameIndex = input.readUnsignedShort();
0229: int typeIndex = input.readUnsignedShort();
0230: int slot = input.readUnsignedShort();
0231: Instruction startInstr = start >= 0
0232: && start < instrs.length ? instrs[start] : null;
0233: Instruction endInstr;
0234: if (end >= 0 && end < instrs.length)
0235: endInstr = instrs[end] == null ? null : instrs[end]
0236: .getPrevByAddr();
0237: else {
0238: endInstr = null;
0239: for (int nr = instrs.length - 1; nr >= 0; nr--) {
0240: if (instrs[nr] != null) {
0241: if (instrs[nr].getNextAddr() == end)
0242: endInstr = instrs[nr];
0243: break;
0244: }
0245: }
0246: }
0247:
0248: if (startInstr == null || endInstr == null
0249: || nameIndex == 0 || typeIndex == 0
0250: || slot >= maxLocals
0251: || cp.getTag(nameIndex) != cp.UTF8
0252: || cp.getTag(typeIndex) != cp.UTF8) {
0253:
0254: // This is probably an evil lvt as created by HashJava
0255: // simply ignore it.
0256: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
0257: GlobalOptions.err
0258: .println("Illegal entry, ignoring LVT");
0259: lvt = null;
0260: return;
0261: }
0262: lvt[i].start = startInstr;
0263: lvt[i].end = endInstr;
0264: lvt[i].name = cp.getUTF8(nameIndex);
0265: lvt[i].type = cp.getUTF8(typeIndex);
0266: lvt[i].slot = slot;
0267: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
0268: GlobalOptions.err.println("\t" + lvt[i].name + ": "
0269: + lvt[i].type + " range " + start + " - "
0270: + end + " slot " + slot);
0271: }
0272: } else if ((howMuch & KNOWNATTRIBS) != 0
0273: && name.equals("LineNumberTable")) {
0274: int count = input.readUnsignedShort();
0275: if (length != 2 + count * 4) {
0276: GlobalOptions.err
0277: .println("Illegal LineNumberTable, ignoring it");
0278: return;
0279: }
0280: lnt = new LineNumber[count];
0281: for (int i = 0; i < count; i++) {
0282: lnt[i] = new LineNumber();
0283: int start = input.readUnsignedShort();
0284: Instruction startInstr = instrs[start];
0285: if (startInstr == null) {
0286: GlobalOptions.err
0287: .println("Illegal entry, ignoring LineNumberTable table");
0288: lnt = null;
0289: return;
0290: }
0291: lnt[i].start = startInstr;
0292: lnt[i].linenr = input.readUnsignedShort();
0293: }
0294: } else
0295: super .readAttribute(name, length, cp, input, howMuch);
0296: }
0297:
0298: public void read(ConstantPool cp, DataInputStream input)
0299: throws IOException {
0300: maxStack = input.readUnsignedShort();
0301: maxLocals = input.readUnsignedShort();
0302: instructions = new InstructionList();
0303: int codeLength = input.readInt();
0304: instrs = new Instruction[codeLength];
0305: int[][] succAddrs = new int[codeLength][];
0306: {
0307: int addr = 0;
0308: while (addr < codeLength) {
0309: Instruction instr;
0310: int length;
0311: int opcode = input.readUnsignedByte();
0312: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0313: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0314: GlobalOptions.err.print(addr + ": "
0315: + opcodeString[opcode]);
0316:
0317: switch (opcode) {
0318: case opc_wide: {
0319: int wideopcode = input.readUnsignedByte();
0320: switch (wideopcode) {
0321: case opc_iload:
0322: case opc_fload:
0323: case opc_aload:
0324: case opc_istore:
0325: case opc_fstore:
0326: case opc_astore: {
0327: int slot = input.readUnsignedShort();
0328: if (slot >= maxLocals)
0329: throw new ClassFormatError(
0330: "Invalid local slot " + slot);
0331: instr = new Instruction(wideopcode);
0332: instr.setLocalSlot(slot);
0333: length = 4;
0334: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0335: GlobalOptions.err.print(" "
0336: + opcodeString[wideopcode] + " "
0337: + slot);
0338: break;
0339: }
0340: case opc_lload:
0341: case opc_dload:
0342: case opc_lstore:
0343: case opc_dstore: {
0344: int slot = input.readUnsignedShort();
0345: if (slot >= maxLocals - 1)
0346: throw new ClassFormatError(
0347: "Invalid local slot " + slot);
0348: instr = new Instruction(wideopcode);
0349: instr.setLocalSlot(slot);
0350: length = 4;
0351: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0352: GlobalOptions.err.print(" "
0353: + opcodeString[wideopcode] + " "
0354: + slot);
0355: break;
0356: }
0357: case opc_ret: {
0358: int slot = input.readUnsignedShort();
0359: if (slot >= maxLocals)
0360: throw new ClassFormatError(
0361: "Invalid local slot " + slot);
0362: instr = new Instruction(wideopcode);
0363: instr.setLocalSlot(slot);
0364: length = 4;
0365: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0366: GlobalOptions.err.print(" ret " + slot);
0367: break;
0368: }
0369: case opc_iinc: {
0370: int slot = input.readUnsignedShort();
0371: if (slot >= maxLocals)
0372: throw new ClassFormatError(
0373: "Invalid local slot " + slot);
0374: instr = new Instruction(wideopcode);
0375: instr.setLocalSlot(slot);
0376: instr.setIncrement(input.readShort());
0377: length = 6;
0378: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0379: GlobalOptions.err.print(" iinc " + slot
0380: + " " + instr.getIncrement());
0381: break;
0382: }
0383: default:
0384: throw new ClassFormatError(
0385: "Invalid wide opcode " + wideopcode);
0386: }
0387: break;
0388: }
0389: case opc_iload_0:
0390: case opc_iload_1:
0391: case opc_iload_2:
0392: case opc_iload_3:
0393: case opc_lload_0:
0394: case opc_lload_1:
0395: case opc_lload_2:
0396: case opc_lload_3:
0397: case opc_fload_0:
0398: case opc_fload_1:
0399: case opc_fload_2:
0400: case opc_fload_3:
0401: case opc_dload_0:
0402: case opc_dload_1:
0403: case opc_dload_2:
0404: case opc_dload_3:
0405: case opc_aload_0:
0406: case opc_aload_1:
0407: case opc_aload_2:
0408: case opc_aload_3: {
0409: int slot = (opcode - opc_iload_0) & 3;
0410: if (slot >= maxLocals)
0411: throw new ClassFormatError(
0412: "Invalid local slot " + slot);
0413: instr = new Instruction(opc_iload
0414: + (opcode - opc_iload_0) / 4);
0415: instr.setLocalSlot(slot);
0416: length = 1;
0417: break;
0418: }
0419: case opc_istore_0:
0420: case opc_istore_1:
0421: case opc_istore_2:
0422: case opc_istore_3:
0423: case opc_fstore_0:
0424: case opc_fstore_1:
0425: case opc_fstore_2:
0426: case opc_fstore_3:
0427: case opc_astore_0:
0428: case opc_astore_1:
0429: case opc_astore_2:
0430: case opc_astore_3: {
0431: int slot = (opcode - opc_istore_0) & 3;
0432: if (slot >= maxLocals)
0433: throw new ClassFormatError(
0434: "Invalid local slot " + slot);
0435: instr = new Instruction(opc_istore
0436: + (opcode - opc_istore_0) / 4);
0437: instr.setLocalSlot(slot);
0438: length = 1;
0439: break;
0440: }
0441: case opc_lstore_0:
0442: case opc_lstore_1:
0443: case opc_lstore_2:
0444: case opc_lstore_3:
0445: case opc_dstore_0:
0446: case opc_dstore_1:
0447: case opc_dstore_2:
0448: case opc_dstore_3: {
0449: int slot = (opcode - opc_istore_0) & 3;
0450: if (slot >= maxLocals - 1)
0451: throw new ClassFormatError(
0452: "Invalid local slot " + slot);
0453: instr = new Instruction(opc_istore
0454: + (opcode - opc_istore_0) / 4);
0455: instr.setLocalSlot(slot);
0456: length = 1;
0457: break;
0458: }
0459: case opc_iload:
0460: case opc_fload:
0461: case opc_aload:
0462: case opc_istore:
0463: case opc_fstore:
0464: case opc_astore: {
0465: int slot = input.readUnsignedByte();
0466: if (slot >= maxLocals)
0467: throw new ClassFormatError(
0468: "Invalid local slot " + slot);
0469: instr = new Instruction(opcode);
0470: instr.setLocalSlot(slot);
0471: length = 2;
0472: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0473: GlobalOptions.err.print(" " + slot);
0474: break;
0475: }
0476: case opc_lstore:
0477: case opc_dstore:
0478: case opc_lload:
0479: case opc_dload: {
0480: int slot = input.readUnsignedByte();
0481: if (slot >= maxLocals - 1)
0482: throw new ClassFormatError(
0483: "Invalid local slot " + slot);
0484: instr = new Instruction(opcode);
0485: instr.setLocalSlot(slot);
0486: length = 2;
0487: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0488: GlobalOptions.err.print(" " + slot);
0489: break;
0490: }
0491: case opc_ret: {
0492: int slot = input.readUnsignedByte();
0493: if (slot >= maxLocals)
0494: throw new ClassFormatError(
0495: "Invalid local slot " + slot);
0496: instr = new Instruction(opcode);
0497: instr.setLocalSlot(slot);
0498: length = 2;
0499: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0500: GlobalOptions.err.print(" " + slot);
0501: break;
0502: }
0503: case opc_aconst_null:
0504: case opc_iconst_m1:
0505: case opc_iconst_0:
0506: case opc_iconst_1:
0507: case opc_iconst_2:
0508: case opc_iconst_3:
0509: case opc_iconst_4:
0510: case opc_iconst_5:
0511: case opc_fconst_0:
0512: case opc_fconst_1:
0513: case opc_fconst_2:
0514: instr = new Instruction(opc_ldc);
0515: instr.setConstant(constants[opcode
0516: - opc_aconst_null]);
0517: length = 1;
0518: break;
0519: case opc_lconst_0:
0520: case opc_lconst_1:
0521: case opc_dconst_0:
0522: case opc_dconst_1:
0523: instr = new Instruction(opc_ldc2_w);
0524: instr.setConstant(constants[opcode
0525: - opc_aconst_null]);
0526: length = 1;
0527: break;
0528: case opc_bipush:
0529: instr = new Instruction(opc_ldc);
0530: instr.setConstant(new Integer(input.readByte()));
0531: length = 2;
0532: break;
0533: case opc_sipush:
0534: instr = new Instruction(opc_ldc);
0535: instr.setConstant(new Integer(input.readShort()));
0536: length = 3;
0537: break;
0538: case opc_ldc: {
0539: int index = input.readUnsignedByte();
0540: int tag = cp.getTag(index);
0541: if (tag != cp.STRING && tag != cp.INTEGER
0542: && tag != cp.FLOAT)
0543: throw new ClassFormatException(
0544: "wrong constant tag: " + tag);
0545: instr = new Instruction(opcode);
0546: instr.setConstant(cp.getConstant(index));
0547: length = 2;
0548: break;
0549: }
0550: case opc_ldc_w: {
0551: int index = input.readUnsignedShort();
0552: int tag = cp.getTag(index);
0553: if (tag != cp.STRING && tag != cp.INTEGER
0554: && tag != cp.FLOAT)
0555: throw new ClassFormatException(
0556: "wrong constant tag: " + tag);
0557: instr = new Instruction(opc_ldc);
0558: instr.setConstant(cp.getConstant(index));
0559: length = 3;
0560: break;
0561: }
0562: case opc_ldc2_w: {
0563: int index = input.readUnsignedShort();
0564: int tag = cp.getTag(index);
0565: if (tag != cp.LONG && tag != cp.DOUBLE)
0566: throw new ClassFormatException(
0567: "wrong constant tag: " + tag);
0568: instr = new Instruction(opcode);
0569: instr.setConstant(cp.getConstant(index));
0570: length = 3;
0571: break;
0572: }
0573: case opc_iinc: {
0574: int slot = input.readUnsignedByte();
0575: if (slot >= maxLocals)
0576: throw new ClassFormatError(
0577: "Invalid local slot " + slot);
0578: instr = new Instruction(opcode);
0579: instr.setLocalSlot(slot);
0580: instr.setIncrement(input.readByte());
0581: length = 3;
0582: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0583: GlobalOptions.err.print(" " + slot + " "
0584: + instr.getIncrement());
0585: break;
0586: }
0587: case opc_goto:
0588: case opc_jsr:
0589: case opc_ifeq:
0590: case opc_ifne:
0591: case opc_iflt:
0592: case opc_ifge:
0593: case opc_ifgt:
0594: case opc_ifle:
0595: case opc_if_icmpeq:
0596: case opc_if_icmpne:
0597: case opc_if_icmplt:
0598: case opc_if_icmpge:
0599: case opc_if_icmpgt:
0600: case opc_if_icmple:
0601: case opc_if_acmpeq:
0602: case opc_if_acmpne:
0603: case opc_ifnull:
0604: case opc_ifnonnull:
0605: instr = new Instruction(opcode);
0606: length = 3;
0607: succAddrs[addr] = new int[] { addr
0608: + input.readShort() };
0609: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0610: GlobalOptions.err.print(" "
0611: + succAddrs[addr][0]);
0612: break;
0613:
0614: case opc_goto_w:
0615: case opc_jsr_w:
0616: instr = new Instruction(opcode
0617: - (opc_goto_w - opc_goto));
0618: length = 5;
0619: succAddrs[addr] = new int[] { addr
0620: + input.readInt() };
0621: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0622: GlobalOptions.err.print(" "
0623: + succAddrs[addr][0]);
0624: break;
0625:
0626: case opc_tableswitch: {
0627: length = 3 - (addr % 4);
0628: input.readFully(new byte[length]);
0629: int def = input.readInt();
0630: int low = input.readInt();
0631: int high = input.readInt();
0632: int[] dests = new int[high - low + 1];
0633: int npairs = 0;
0634: for (int i = 0; i < dests.length; i++) {
0635: dests[i] = input.readInt();
0636: if (dests[i] != def)
0637: npairs++;
0638: }
0639: instr = new Instruction(opc_lookupswitch);
0640: succAddrs[addr] = new int[npairs + 1];
0641: int[] values = new int[npairs];
0642: int pos = 0;
0643: for (int i = 0; i < dests.length; i++) {
0644: if (dests[i] != def) {
0645: values[pos] = i + low;
0646: succAddrs[addr][pos] = addr + dests[i];
0647: pos++;
0648: }
0649: }
0650: succAddrs[addr][npairs] = addr + def;
0651: instr.setValues(values);
0652: length += 13 + 4 * (high - low + 1);
0653: break;
0654: }
0655: case opc_lookupswitch: {
0656: length = 3 - (addr % 4);
0657: input.readFully(new byte[length]);
0658: int def = input.readInt();
0659: int npairs = input.readInt();
0660: instr = new Instruction(opcode);
0661: succAddrs[addr] = new int[npairs + 1];
0662: int[] values = new int[npairs];
0663: for (int i = 0; i < npairs; i++) {
0664: values[i] = input.readInt();
0665: if (i > 0 && values[i - 1] >= values[i])
0666: throw new ClassFormatException(
0667: "lookupswitch not sorted");
0668: succAddrs[addr][i] = addr + input.readInt();
0669: }
0670: succAddrs[addr][npairs] = addr + def;
0671: instr.setValues(values);
0672: length += 9 + 8 * npairs;
0673: break;
0674: }
0675:
0676: case opc_getstatic:
0677: case opc_getfield:
0678: case opc_putstatic:
0679: case opc_putfield:
0680: case opc_invokespecial:
0681: case opc_invokestatic:
0682: case opc_invokevirtual: {
0683: int index = input.readUnsignedShort();
0684: int tag = cp.getTag(index);
0685: if (opcode < opc_invokevirtual) {
0686: if (tag != cp.FIELDREF)
0687: throw new ClassFormatException(
0688: "field tag mismatch: " + tag);
0689: } else {
0690: if (tag != cp.METHODREF)
0691: throw new ClassFormatException(
0692: "method tag mismatch: " + tag);
0693: }
0694: Reference ref = cp.getRef(index);
0695: if (ref.getName().charAt(0) == '<'
0696: && (!ref.getName().equals("<init>") || opcode != opc_invokespecial))
0697: throw new ClassFormatException(
0698: "Illegal call of special method/field "
0699: + ref);
0700: instr = new Instruction(opcode);
0701: instr.setReference(ref);
0702: length = 3;
0703: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0704: GlobalOptions.err.print(" " + ref);
0705: break;
0706: }
0707: case opc_invokeinterface: {
0708: int index = input.readUnsignedShort();
0709: int tag = cp.getTag(index);
0710: if (tag != cp.INTERFACEMETHODREF)
0711: throw new ClassFormatException(
0712: "interface tag mismatch: " + tag);
0713: Reference ref = cp.getRef(index);
0714: if (ref.getName().charAt(0) == '<')
0715: throw new ClassFormatException(
0716: "Illegal call of special method " + ref);
0717: int nargs = input.readUnsignedByte();
0718: if (TypeSignature.getArgumentSize(ref.getType()) != nargs - 1)
0719: throw new ClassFormatException(
0720: "Interface nargs mismatch: " + ref
0721: + " vs. " + nargs);
0722: if (input.readUnsignedByte() != 0)
0723: throw new ClassFormatException(
0724: "Interface reserved param not zero");
0725:
0726: instr = new Instruction(opcode);
0727: instr.setReference(ref);
0728: length = 5;
0729: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0730: GlobalOptions.err.print(" " + ref);
0731: break;
0732: }
0733:
0734: case opc_new:
0735: case opc_checkcast:
0736: case opc_instanceof : {
0737: String type = cp.getClassType(input
0738: .readUnsignedShort());
0739: if (opcode == opc_new && type.charAt(0) == '[')
0740: throw new ClassFormatException(
0741: "Can't create array with opc_new");
0742: instr = new Instruction(opcode);
0743: instr.setClazzType(type);
0744: length = 3;
0745: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0746: GlobalOptions.err.print(" " + type);
0747: break;
0748: }
0749: case opc_multianewarray: {
0750: String type = cp.getClassType(input
0751: .readUnsignedShort());
0752: int dims = input.readUnsignedByte();
0753: if (dims == 0)
0754: throw new ClassFormatException(
0755: "multianewarray dimension is 0.");
0756: for (int i = 0; i < dims; i++) {
0757: /* Note that since type is a valid type
0758: * signature, there must be a non bracket
0759: * character, before the string is over.
0760: * So there is no StringIndexOutOfBoundsException.
0761: */
0762: if (type.charAt(i) != '[')
0763: throw new ClassFormatException(
0764: "multianewarray called for non array:"
0765: + type);
0766: }
0767: instr = new Instruction(opcode);
0768: instr.setClazzType(type);
0769: instr.setDimensions(dims);
0770: length = 4;
0771: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0772: GlobalOptions.err
0773: .print(" " + type + " " + dims);
0774: break;
0775: }
0776: case opc_anewarray: {
0777: String type = cp.getClassType(input
0778: .readUnsignedShort());
0779: instr = new Instruction(opc_multianewarray);
0780: instr.setClazzType(("[" + type).intern());
0781: instr.setDimensions(1);
0782: length = 3;
0783: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0784: GlobalOptions.err.print(" " + type);
0785: break;
0786: }
0787: case opc_newarray: {
0788: char sig = newArrayTypes.charAt(input
0789: .readUnsignedByte() - 4);
0790: String type = new String(new char[] { '[', sig });
0791: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0792: GlobalOptions.err.print(" " + type);
0793: instr = new Instruction(opc_multianewarray);
0794: instr.setClazzType(type);
0795: instr.setDimensions(1);
0796: length = 2;
0797: break;
0798: }
0799:
0800: case opc_nop:
0801: case opc_iaload:
0802: case opc_laload:
0803: case opc_faload:
0804: case opc_daload:
0805: case opc_aaload:
0806: case opc_baload:
0807: case opc_caload:
0808: case opc_saload:
0809: case opc_iastore:
0810: case opc_lastore:
0811: case opc_fastore:
0812: case opc_dastore:
0813: case opc_aastore:
0814: case opc_bastore:
0815: case opc_castore:
0816: case opc_sastore:
0817: case opc_pop:
0818: case opc_pop2:
0819: case opc_dup:
0820: case opc_dup_x1:
0821: case opc_dup_x2:
0822: case opc_dup2:
0823: case opc_dup2_x1:
0824: case opc_dup2_x2:
0825: case opc_swap:
0826: case opc_iadd:
0827: case opc_ladd:
0828: case opc_fadd:
0829: case opc_dadd:
0830: case opc_isub:
0831: case opc_lsub:
0832: case opc_fsub:
0833: case opc_dsub:
0834: case opc_imul:
0835: case opc_lmul:
0836: case opc_fmul:
0837: case opc_dmul:
0838: case opc_idiv:
0839: case opc_ldiv:
0840: case opc_fdiv:
0841: case opc_ddiv:
0842: case opc_irem:
0843: case opc_lrem:
0844: case opc_frem:
0845: case opc_drem:
0846: case opc_ineg:
0847: case opc_lneg:
0848: case opc_fneg:
0849: case opc_dneg:
0850: case opc_ishl:
0851: case opc_lshl:
0852: case opc_ishr:
0853: case opc_lshr:
0854: case opc_iushr:
0855: case opc_lushr:
0856: case opc_iand:
0857: case opc_land:
0858: case opc_ior:
0859: case opc_lor:
0860: case opc_ixor:
0861: case opc_lxor:
0862: case opc_i2l:
0863: case opc_i2f:
0864: case opc_i2d:
0865: case opc_l2i:
0866: case opc_l2f:
0867: case opc_l2d:
0868: case opc_f2i:
0869: case opc_f2l:
0870: case opc_f2d:
0871: case opc_d2i:
0872: case opc_d2l:
0873: case opc_d2f:
0874: case opc_i2b:
0875: case opc_i2c:
0876: case opc_i2s:
0877: case opc_lcmp:
0878: case opc_fcmpl:
0879: case opc_fcmpg:
0880: case opc_dcmpl:
0881: case opc_dcmpg:
0882: case opc_ireturn:
0883: case opc_lreturn:
0884: case opc_freturn:
0885: case opc_dreturn:
0886: case opc_areturn:
0887: case opc_return:
0888: case opc_athrow:
0889: case opc_arraylength:
0890: case opc_monitorenter:
0891: case opc_monitorexit:
0892: instr = new Instruction(opcode);
0893: length = 1;
0894: break;
0895: default:
0896: throw new ClassFormatError("Invalid opcode "
0897: + opcode);
0898: }
0899: if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_BYTECODE) != 0)
0900: GlobalOptions.err.println();
0901:
0902: instrs[addr] = instr;
0903: instructions.add(instr);
0904:
0905: addr += length;
0906: instructions.setLastAddr(addr);
0907: }
0908: if (addr != codeLength)
0909: throw new ClassFormatError("last instruction too long");
0910: }
0911: for (Iterator iter = instructions.iterator(); iter.hasNext();) {
0912: Instruction instr = (Instruction) iter.next();
0913: int addr = instr.getAddr();
0914: if (succAddrs[addr] != null) {
0915: int length = succAddrs[addr].length;
0916: Instruction[] succs = new Instruction[length];
0917: for (int i = 0; i < length; i++) {
0918: int succAddr = succAddrs[addr][i];
0919: if (succAddr < 0 || succAddr > codeLength
0920: || instrs[succAddr] == null)
0921: throw new ClassFormatException(
0922: "Illegal jump target at " + this + "@"
0923: + addr);
0924: succs[i] = instrs[succAddr];
0925: }
0926: instr.setSuccs(succs);
0927: }
0928: }
0929: succAddrs = null;
0930:
0931: {
0932: int handlersLength = input.readUnsignedShort();
0933: exceptionHandlers = new Handler[handlersLength];
0934: for (int i = 0; i < handlersLength; i++) {
0935: exceptionHandlers[i] = new Handler();
0936: exceptionHandlers[i].start = instrs[input
0937: .readUnsignedShort()];
0938: exceptionHandlers[i].end = instrs[input
0939: .readUnsignedShort()].getPrevByAddr();
0940: exceptionHandlers[i].catcher = instrs[input
0941: .readUnsignedShort()];
0942: int index = input.readUnsignedShort();
0943: exceptionHandlers[i].type = (index == 0) ? null : cp
0944: .getClassName(index);
0945:
0946: if (exceptionHandlers[i].catcher.getOpcode() == opc_athrow) {
0947: /* There is an obfuscator, which inserts bogus
0948: * exception entries jumping directly to a throw
0949: * instruction. Remove those handlers.
0950: */
0951: handlersLength--;
0952: i--;
0953: continue;
0954: }
0955:
0956: if (exceptionHandlers[i].start.getAddr() <= exceptionHandlers[i].catcher
0957: .getAddr()
0958: && exceptionHandlers[i].end.getAddr() >= exceptionHandlers[i].catcher
0959: .getAddr()) {
0960: /* Javac 1.4 is a bit paranoid with finally and
0961: * synchronize blocks and even breaks the JLS.
0962: * We fix it here. Hopefully this won't produce
0963: * any other problems.
0964: */
0965: if (exceptionHandlers[i].start == exceptionHandlers[i].catcher) {
0966: handlersLength--;
0967: i--;
0968: } else {
0969: exceptionHandlers[i].end = exceptionHandlers[i].catcher
0970: .getPrevByAddr();
0971: }
0972: }
0973: }
0974: if (handlersLength < exceptionHandlers.length) {
0975: Handler[] newHandlers = new Handler[handlersLength];
0976: System.arraycopy(exceptionHandlers, 0, newHandlers, 0,
0977: handlersLength);
0978: exceptionHandlers = newHandlers;
0979: }
0980: }
0981: readAttributes(cp, input, FULLINFO);
0982: instrs = null;
0983: }
0984:
0985: public void dumpCode(java.io.PrintWriter output) {
0986: for (Iterator iter = instructions.iterator(); iter.hasNext();) {
0987: Instruction instr = (Instruction) iter.next();
0988: output.println(instr.getDescription() + " "
0989: + Integer.toHexString(hashCode()));
0990: Instruction[] succs = instr.getSuccs();
0991: if (succs != null) {
0992: output.print("\tsuccs: " + succs[0]);
0993: for (int i = 1; i < succs.length; i++)
0994: output.print(", " + succs[i]);
0995: output.println();
0996: }
0997: if (instr.getPreds() != null) {
0998: output.print("\tpreds: " + instr.getPreds()[0]);
0999: for (int i = 1; i < instr.getPreds().length; i++)
1000: output.print(", " + instr.getPreds()[i]);
1001: output.println();
1002: }
1003: }
1004: for (int i = 0; i < exceptionHandlers.length; i++) {
1005: output.println("catch " + exceptionHandlers[i].type
1006: + " from " + exceptionHandlers[i].start + " to "
1007: + exceptionHandlers[i].end + " catcher "
1008: + exceptionHandlers[i].catcher);
1009: }
1010: }
1011:
1012: public void reserveSmallConstants(GrowableConstantPool gcp) {
1013: next_instr: for (Iterator iter = instructions.iterator(); iter
1014: .hasNext();) {
1015: Instruction instr = (Instruction) iter.next();
1016: if (instr.getOpcode() == opc_ldc) {
1017: Object constant = instr.getConstant();
1018: if (constant == null)
1019: continue next_instr;
1020: for (int i = 1; i < constants.length; i++) {
1021: if (constant.equals(constants[i]))
1022: continue next_instr;
1023: }
1024: if (constant instanceof Integer) {
1025: int value = ((Integer) constant).intValue();
1026: if (value >= Short.MIN_VALUE
1027: && value <= Short.MAX_VALUE)
1028: continue next_instr;
1029: }
1030: gcp.reserveConstant(constant);
1031: }
1032: }
1033: }
1034:
1035: private void calculateMaxStack() {
1036: maxStack = 0;
1037: int[] stackHeights = new int[instructions.getCodeLength()];
1038: int[] poppush = new int[2];
1039: Stack todo = new Stack();
1040:
1041: for (int i = 0; i < stackHeights.length; i++)
1042: stackHeights[i] = -1;
1043:
1044: stackHeights[0] = 0;
1045: todo.push(instructions.get(0));
1046: while (!todo.isEmpty()) {
1047: Instruction instr = (Instruction) todo.pop();
1048: Instruction next = instr.getNextByAddr();
1049: Instruction[] succs = instr.getSuccs();
1050: int addr = instr.getAddr();
1051: instr.getStackPopPush(poppush);
1052: int sh = stackHeights[addr] - poppush[0] + poppush[1];
1053: // System.err.println("Instr: "+instr.getDescription()+
1054: // "; before: "+stackHeights[addr]+" after: "+sh);
1055: if (maxStack < sh)
1056: maxStack = sh;
1057: if (instr.getOpcode() == opc_jsr) {
1058: if (stackHeights[next.getAddr()] == -1) {
1059: stackHeights[next.getAddr()] = sh - 1;
1060: todo.push(next);
1061: }
1062: if (stackHeights[succs[0].getAddr()] == -1) {
1063: stackHeights[succs[0].getAddr()] = sh;
1064: todo.push(succs[0]);
1065: }
1066: } else {
1067: if (succs != null) {
1068: for (int i = 0; i < succs.length; i++) {
1069: if (stackHeights[succs[i].getAddr()] == -1) {
1070: stackHeights[succs[i].getAddr()] = sh;
1071: todo.push(succs[i]);
1072: }
1073: }
1074: }
1075: if (!instr.doesAlwaysJump()
1076: && stackHeights[next.getAddr()] == -1) {
1077: stackHeights[next.getAddr()] = sh;
1078: todo.push(next);
1079: }
1080: }
1081: for (int i = 0; i < exceptionHandlers.length; i++) {
1082: if (exceptionHandlers[i].start.compareTo(instr) <= 0
1083: && exceptionHandlers[i].end.compareTo(instr) >= 0) {
1084: int catcher = exceptionHandlers[i].catcher
1085: .getAddr();
1086: if (stackHeights[catcher] == -1) {
1087: stackHeights[catcher] = 1;
1088: todo.push(exceptionHandlers[i].catcher);
1089: }
1090: }
1091: }
1092: }
1093: // System.err.println("New maxStack: "+maxStack+" Locals: "+maxLocals);
1094: }
1095:
1096: public void prepareWriting(GrowableConstantPool gcp) {
1097: /* Recalculate addr, length, maxStack, maxLocals and add all
1098: * constants to gcp */
1099: int addr = 0;
1100: maxLocals = (methodInfo.isStatic() ? 0 : 1)
1101: + TypeSignature.getArgumentSize(methodInfo.getType());
1102:
1103: for (Iterator iter = instructions.iterator(); iter.hasNext();) {
1104: Instruction instr = (Instruction) iter.next();
1105: int opcode = instr.getOpcode();
1106: instr.setAddr(addr);
1107: int length;
1108: switch_opc: switch (opcode) {
1109: case opc_ldc:
1110: case opc_ldc2_w: {
1111: Object constant = instr.getConstant();
1112: if (constant == null) {
1113: length = 1;
1114: break switch_opc;
1115: }
1116: for (int i = 1; i < constants.length; i++) {
1117: if (constant.equals(constants[i])) {
1118: length = 1;
1119: break switch_opc;
1120: }
1121: }
1122: if (opcode == opc_ldc2_w) {
1123: gcp.putLongConstant(constant);
1124: length = 3;
1125: break switch_opc;
1126: }
1127: if (constant instanceof Integer) {
1128: int value = ((Integer) constant).intValue();
1129: if (value >= Byte.MIN_VALUE
1130: && value <= Byte.MAX_VALUE) {
1131: length = 2;
1132: break switch_opc;
1133: } else if (value >= Short.MIN_VALUE
1134: && value <= Short.MAX_VALUE) {
1135: length = 3;
1136: break switch_opc;
1137: }
1138: }
1139: if (gcp.putConstant(constant) < 256) {
1140: length = 2;
1141: } else {
1142: length = 3;
1143: }
1144: break;
1145: }
1146: case opc_iinc: {
1147: int slot = instr.getLocalSlot();
1148: int increment = instr.getIncrement();
1149: if (slot < 256 && increment >= Byte.MIN_VALUE
1150: && increment <= Byte.MAX_VALUE)
1151: length = 3;
1152: else
1153: length = 6;
1154: if (slot >= maxLocals)
1155: maxLocals = slot + 1;
1156: break;
1157: }
1158: case opc_iload:
1159: case opc_fload:
1160: case opc_aload:
1161: case opc_istore:
1162: case opc_fstore:
1163: case opc_astore: {
1164: int slot = instr.getLocalSlot();
1165: if (slot < 4)
1166: length = 1;
1167: else if (slot < 256)
1168: length = 2;
1169: else
1170: length = 4;
1171: if (slot >= maxLocals)
1172: maxLocals = slot + 1;
1173: break;
1174: }
1175: case opc_lload:
1176: case opc_dload:
1177: case opc_lstore:
1178: case opc_dstore: {
1179: int slot = instr.getLocalSlot();
1180: if (slot < 4)
1181: length = 1;
1182: else if (slot < 256)
1183: length = 2;
1184: else
1185: length = 4;
1186: if (slot + 1 >= maxLocals)
1187: maxLocals = slot + 2;
1188: break;
1189: }
1190: case opc_ret: {
1191: int slot = instr.getLocalSlot();
1192: if (slot < 256)
1193: length = 2;
1194: else
1195: length = 4;
1196: if (slot >= maxLocals)
1197: maxLocals = slot + 1;
1198: break;
1199: }
1200: case opc_lookupswitch: {
1201: length = 3 - (addr % 4);
1202: int[] values = instr.getValues();
1203: int npairs = values.length;
1204: if (npairs > 0) {
1205: int tablesize = values[npairs - 1] - values[0] + 1;
1206: if (4 + tablesize * 4 < 8 * npairs) {
1207: // Use a table switch
1208: length += 13 + 4 * tablesize;
1209: break;
1210: }
1211: }
1212: // Use a lookup switch
1213: length += 9 + 8 * npairs;
1214: break;
1215: }
1216: case opc_goto:
1217: case opc_jsr: {
1218: int dist = instr.getSingleSucc().getAddr()
1219: - instr.getAddr();
1220: if (dist < Short.MIN_VALUE || dist > Short.MAX_VALUE) {
1221: /* wide goto / jsr */
1222: length = 5;
1223: break;
1224: }
1225: /* fall through */
1226: }
1227: case opc_ifeq:
1228: case opc_ifne:
1229: case opc_iflt:
1230: case opc_ifge:
1231: case opc_ifgt:
1232: case opc_ifle:
1233: case opc_if_icmpeq:
1234: case opc_if_icmpne:
1235: case opc_if_icmplt:
1236: case opc_if_icmpge:
1237: case opc_if_icmpgt:
1238: case opc_if_icmple:
1239: case opc_if_acmpeq:
1240: case opc_if_acmpne:
1241: case opc_ifnull:
1242: case opc_ifnonnull:
1243: length = 3;
1244: break;
1245: case opc_multianewarray: {
1246: if (instr.getDimensions() == 1) {
1247: String clazz = instr.getClazzType().substring(1);
1248: if (newArrayTypes.indexOf(clazz.charAt(0)) != -1) {
1249: length = 2;
1250: } else {
1251: gcp.putClassType(clazz);
1252: length = 3;
1253: }
1254: } else {
1255: gcp.putClassType(instr.getClazzType());
1256: length = 4;
1257: }
1258: break;
1259: }
1260: case opc_getstatic:
1261: case opc_getfield:
1262: case opc_putstatic:
1263: case opc_putfield:
1264: gcp.putRef(gcp.FIELDREF, instr.getReference());
1265: length = 3;
1266: break;
1267: case opc_invokespecial:
1268: case opc_invokestatic:
1269: case opc_invokevirtual:
1270: gcp.putRef(gcp.METHODREF, instr.getReference());
1271: length = 3;
1272: break;
1273: case opc_invokeinterface:
1274: gcp
1275: .putRef(gcp.INTERFACEMETHODREF, instr
1276: .getReference());
1277: length = 5;
1278: break;
1279: case opc_new:
1280: case opc_checkcast:
1281: case opc_instanceof :
1282: gcp.putClassType(instr.getClazzType());
1283: length = 3;
1284: break;
1285: case opc_nop:
1286: case opc_iaload:
1287: case opc_laload:
1288: case opc_faload:
1289: case opc_daload:
1290: case opc_aaload:
1291: case opc_baload:
1292: case opc_caload:
1293: case opc_saload:
1294: case opc_iastore:
1295: case opc_lastore:
1296: case opc_fastore:
1297: case opc_dastore:
1298: case opc_aastore:
1299: case opc_bastore:
1300: case opc_castore:
1301: case opc_sastore:
1302: case opc_pop:
1303: case opc_pop2:
1304: case opc_dup:
1305: case opc_dup_x1:
1306: case opc_dup_x2:
1307: case opc_dup2:
1308: case opc_dup2_x1:
1309: case opc_dup2_x2:
1310: case opc_swap:
1311: case opc_iadd:
1312: case opc_ladd:
1313: case opc_fadd:
1314: case opc_dadd:
1315: case opc_isub:
1316: case opc_lsub:
1317: case opc_fsub:
1318: case opc_dsub:
1319: case opc_imul:
1320: case opc_lmul:
1321: case opc_fmul:
1322: case opc_dmul:
1323: case opc_idiv:
1324: case opc_ldiv:
1325: case opc_fdiv:
1326: case opc_ddiv:
1327: case opc_irem:
1328: case opc_lrem:
1329: case opc_frem:
1330: case opc_drem:
1331: case opc_ineg:
1332: case opc_lneg:
1333: case opc_fneg:
1334: case opc_dneg:
1335: case opc_ishl:
1336: case opc_lshl:
1337: case opc_ishr:
1338: case opc_lshr:
1339: case opc_iushr:
1340: case opc_lushr:
1341: case opc_iand:
1342: case opc_land:
1343: case opc_ior:
1344: case opc_lor:
1345: case opc_ixor:
1346: case opc_lxor:
1347: case opc_i2l:
1348: case opc_i2f:
1349: case opc_i2d:
1350: case opc_l2i:
1351: case opc_l2f:
1352: case opc_l2d:
1353: case opc_f2i:
1354: case opc_f2l:
1355: case opc_f2d:
1356: case opc_d2i:
1357: case opc_d2l:
1358: case opc_d2f:
1359: case opc_i2b:
1360: case opc_i2c:
1361: case opc_i2s:
1362: case opc_lcmp:
1363: case opc_fcmpl:
1364: case opc_fcmpg:
1365: case opc_dcmpl:
1366: case opc_dcmpg:
1367: case opc_ireturn:
1368: case opc_lreturn:
1369: case opc_freturn:
1370: case opc_dreturn:
1371: case opc_areturn:
1372: case opc_return:
1373: case opc_athrow:
1374: case opc_arraylength:
1375: case opc_monitorenter:
1376: case opc_monitorexit:
1377: length = 1;
1378: break;
1379: default:
1380: throw new ClassFormatError("Invalid opcode " + opcode);
1381: }
1382: addr += length;
1383: }
1384: instructions.setLastAddr(addr);
1385: try {
1386: calculateMaxStack();
1387: } catch (RuntimeException ex) {
1388: ex.printStackTrace();
1389: dumpCode(GlobalOptions.err);
1390: }
1391: for (int i = 0; i < exceptionHandlers.length; i++)
1392: if (exceptionHandlers[i].type != null)
1393: gcp.putClassName(exceptionHandlers[i].type);
1394: if (lvt != null) {
1395: gcp.putUTF8("LocalVariableTable");
1396: for (int i = 0; i < lvt.length; i++) {
1397: gcp.putUTF8(lvt[i].name);
1398: gcp.putUTF8(lvt[i].type);
1399: }
1400: }
1401: if (lnt != null)
1402: gcp.putUTF8("LineNumberTable");
1403: prepareAttributes(gcp);
1404: }
1405:
1406: protected int getKnownAttributeCount() {
1407: int count = 0;
1408: if (lvt != null)
1409: count++;
1410: if (lnt != null)
1411: count++;
1412: return count;
1413: }
1414:
1415: public void writeKnownAttributes(GrowableConstantPool gcp,
1416: DataOutputStream output) throws IOException {
1417: if (lvt != null) {
1418: output.writeShort(gcp.putUTF8("LocalVariableTable"));
1419: int count = lvt.length;
1420: int length = 2 + 10 * count;
1421: output.writeInt(length);
1422: output.writeShort(count);
1423: for (int i = 0; i < count; i++) {
1424: output.writeShort(lvt[i].start.getAddr());
1425: output.writeShort(lvt[i].end.getAddr()
1426: + lvt[i].end.getLength()
1427: - lvt[i].start.getAddr());
1428: output.writeShort(gcp.putUTF8(lvt[i].name));
1429: output.writeShort(gcp.putUTF8(lvt[i].type));
1430: output.writeShort(lvt[i].slot);
1431: }
1432: }
1433: if (lnt != null) {
1434: output.writeShort(gcp.putUTF8("LineNumberTable"));
1435: int count = lnt.length;
1436: int length = 2 + 4 * count;
1437: output.writeInt(length);
1438: output.writeShort(count);
1439: for (int i = 0; i < count; i++) {
1440: output.writeShort(lnt[i].start.getAddr());
1441: output.writeShort(lnt[i].linenr);
1442: }
1443: }
1444: }
1445:
1446: public void write(GrowableConstantPool gcp, DataOutputStream output)
1447: throws IOException {
1448: output.writeShort(maxStack);
1449: output.writeShort(maxLocals);
1450: output.writeInt(instructions.getCodeLength());
1451: for (Iterator iter = instructions.iterator(); iter.hasNext();) {
1452: Instruction instr = (Instruction) iter.next();
1453: int opcode = instr.getOpcode();
1454: switch_opc: switch (opcode) {
1455: case opc_iload:
1456: case opc_lload:
1457: case opc_fload:
1458: case opc_dload:
1459: case opc_aload:
1460: case opc_istore:
1461: case opc_lstore:
1462: case opc_fstore:
1463: case opc_dstore:
1464: case opc_astore: {
1465: int slot = instr.getLocalSlot();
1466: if (slot < 4) {
1467: if (opcode < opc_istore)
1468: output.writeByte(opc_iload_0 + 4
1469: * (opcode - opc_iload) + slot);
1470: else
1471: output.writeByte(opc_istore_0 + 4
1472: * (opcode - opc_istore) + slot);
1473: } else if (slot < 256) {
1474: output.writeByte(opcode);
1475: output.writeByte(slot);
1476: } else {
1477: output.writeByte(opc_wide);
1478: output.writeByte(opcode);
1479: output.writeShort(slot);
1480: }
1481: break;
1482: }
1483: case opc_ret: {
1484: int slot = instr.getLocalSlot();
1485: if (slot < 256) {
1486: output.writeByte(opcode);
1487: output.writeByte(slot);
1488: } else {
1489: output.writeByte(opc_wide);
1490: output.writeByte(opcode);
1491: output.writeShort(slot);
1492: }
1493: break;
1494: }
1495: case opc_ldc:
1496: case opc_ldc2_w: {
1497: Object constant = instr.getConstant();
1498: if (constant == null) {
1499: output.writeByte(opc_aconst_null);
1500: break switch_opc;
1501: }
1502: for (int i = 1; i < constants.length; i++) {
1503: if (constant.equals(constants[i])) {
1504: output.writeByte(opc_aconst_null + i);
1505: break switch_opc;
1506: }
1507: }
1508: if (opcode == opc_ldc2_w) {
1509: output.writeByte(opcode);
1510: output.writeShort(gcp.putLongConstant(constant));
1511: } else {
1512: if (constant instanceof Integer) {
1513: int value = ((Integer) constant).intValue();
1514: if (value >= Byte.MIN_VALUE
1515: && value <= Byte.MAX_VALUE) {
1516:
1517: output.writeByte(opc_bipush);
1518: output.writeByte(((Integer) constant)
1519: .intValue());
1520: break switch_opc;
1521: } else if (value >= Short.MIN_VALUE
1522: && value <= Short.MAX_VALUE) {
1523: output.writeByte(opc_sipush);
1524: output.writeShort(((Integer) constant)
1525: .intValue());
1526: break switch_opc;
1527: }
1528: }
1529: if (instr.getLength() == 2) {
1530: output.writeByte(opc_ldc);
1531: output.writeByte(gcp.putConstant(constant));
1532: } else {
1533: output.writeByte(opc_ldc_w);
1534: output.writeShort(gcp.putConstant(constant));
1535: }
1536: }
1537: break;
1538: }
1539: case opc_iinc: {
1540: int slot = instr.getLocalSlot();
1541: int incr = instr.getIncrement();
1542: if (instr.getLength() == 3) {
1543: output.writeByte(opcode);
1544: output.writeByte(slot);
1545: output.writeByte(incr);
1546: } else {
1547: output.writeByte(opc_wide);
1548: output.writeByte(opcode);
1549: output.writeShort(slot);
1550: output.writeShort(incr);
1551: }
1552: break;
1553: }
1554: case opc_goto:
1555: case opc_jsr:
1556: if (instr.getLength() == 5) {
1557: /* wide goto or jsr */
1558: output.writeByte(opcode + (opc_goto_w - opc_goto));
1559: output.writeInt(instr.getSingleSucc().getAddr()
1560: - instr.getAddr());
1561: break;
1562: }
1563: /* fall through */
1564: case opc_ifeq:
1565: case opc_ifne:
1566: case opc_iflt:
1567: case opc_ifge:
1568: case opc_ifgt:
1569: case opc_ifle:
1570: case opc_if_icmpeq:
1571: case opc_if_icmpne:
1572: case opc_if_icmplt:
1573: case opc_if_icmpge:
1574: case opc_if_icmpgt:
1575: case opc_if_icmple:
1576: case opc_if_acmpeq:
1577: case opc_if_acmpne:
1578: case opc_ifnull:
1579: case opc_ifnonnull:
1580: output.writeByte(opcode);
1581: output.writeShort(instr.getSingleSucc().getAddr()
1582: - instr.getAddr());
1583: break;
1584:
1585: case opc_lookupswitch: {
1586: int align = 3 - (instr.getAddr() % 4);
1587: int[] values = instr.getValues();
1588: int npairs = values.length;
1589: int defAddr = instr.getSuccs()[npairs].getAddr()
1590: - instr.getAddr();
1591:
1592: if (npairs > 0) {
1593: int tablesize = values[npairs - 1] - values[0] + 1;
1594: if (4 + tablesize * 4 < 8 * npairs) {
1595: // Use a table switch
1596: output.writeByte(opc_tableswitch);
1597: output.write(new byte[align]);
1598: /* def */
1599: output.writeInt(defAddr);
1600: /* low */
1601: output.writeInt(values[0]);
1602: /* high */
1603: output.writeInt(values[npairs - 1]);
1604: int pos = values[0];
1605: for (int i = 0; i < npairs; i++) {
1606: while (pos++ < values[i])
1607: output.writeInt(defAddr);
1608: output.writeInt(instr.getSuccs()[i]
1609: .getAddr()
1610: - instr.getAddr());
1611: }
1612: break;
1613: }
1614: }
1615: // Use a lookup switch
1616: output.writeByte(opc_lookupswitch);
1617: output.write(new byte[align]);
1618: /* def */
1619: output.writeInt(defAddr);
1620: output.writeInt(npairs);
1621: for (int i = 0; i < npairs; i++) {
1622: output.writeInt(values[i]);
1623: output.writeInt(instr.getSuccs()[i].getAddr()
1624: - instr.getAddr());
1625: }
1626: break;
1627: }
1628:
1629: case opc_getstatic:
1630: case opc_getfield:
1631: case opc_putstatic:
1632: case opc_putfield:
1633: output.writeByte(opcode);
1634: output.writeShort(gcp.putRef(gcp.FIELDREF, instr
1635: .getReference()));
1636: break;
1637:
1638: case opc_invokespecial:
1639: case opc_invokestatic:
1640: case opc_invokeinterface:
1641: case opc_invokevirtual: {
1642: Reference ref = instr.getReference();
1643: output.writeByte(opcode);
1644: if (opcode == opc_invokeinterface) {
1645: output.writeShort(gcp.putRef(
1646: gcp.INTERFACEMETHODREF, ref));
1647: output.writeByte(TypeSignature.getArgumentSize(ref
1648: .getType()) + 1);
1649: output.writeByte(0);
1650: } else
1651: output.writeShort(gcp.putRef(gcp.METHODREF, ref));
1652: break;
1653: }
1654: case opc_new:
1655: case opc_checkcast:
1656: case opc_instanceof :
1657: output.writeByte(opcode);
1658: output.writeShort(gcp
1659: .putClassType(instr.getClazzType()));
1660: break;
1661: case opc_multianewarray:
1662: if (instr.getDimensions() == 1) {
1663: String clazz = instr.getClazzType().substring(1);
1664: int index = newArrayTypes.indexOf(clazz.charAt(0));
1665: if (index != -1) {
1666: output.writeByte(opc_newarray);
1667: output.writeByte(index + 4);
1668: } else {
1669: output.writeByte(opc_anewarray);
1670: output.writeShort(gcp.putClassType(clazz));
1671: }
1672: } else {
1673: output.writeByte(opcode);
1674: output.writeShort(gcp.putClassType(instr
1675: .getClazzType()));
1676: output.writeByte(instr.getDimensions());
1677: }
1678: break;
1679:
1680: case opc_nop:
1681: case opc_iaload:
1682: case opc_laload:
1683: case opc_faload:
1684: case opc_daload:
1685: case opc_aaload:
1686: case opc_baload:
1687: case opc_caload:
1688: case opc_saload:
1689: case opc_iastore:
1690: case opc_lastore:
1691: case opc_fastore:
1692: case opc_dastore:
1693: case opc_aastore:
1694: case opc_bastore:
1695: case opc_castore:
1696: case opc_sastore:
1697: case opc_pop:
1698: case opc_pop2:
1699: case opc_dup:
1700: case opc_dup_x1:
1701: case opc_dup_x2:
1702: case opc_dup2:
1703: case opc_dup2_x1:
1704: case opc_dup2_x2:
1705: case opc_swap:
1706: case opc_iadd:
1707: case opc_ladd:
1708: case opc_fadd:
1709: case opc_dadd:
1710: case opc_isub:
1711: case opc_lsub:
1712: case opc_fsub:
1713: case opc_dsub:
1714: case opc_imul:
1715: case opc_lmul:
1716: case opc_fmul:
1717: case opc_dmul:
1718: case opc_idiv:
1719: case opc_ldiv:
1720: case opc_fdiv:
1721: case opc_ddiv:
1722: case opc_irem:
1723: case opc_lrem:
1724: case opc_frem:
1725: case opc_drem:
1726: case opc_ineg:
1727: case opc_lneg:
1728: case opc_fneg:
1729: case opc_dneg:
1730: case opc_ishl:
1731: case opc_lshl:
1732: case opc_ishr:
1733: case opc_lshr:
1734: case opc_iushr:
1735: case opc_lushr:
1736: case opc_iand:
1737: case opc_land:
1738: case opc_ior:
1739: case opc_lor:
1740: case opc_ixor:
1741: case opc_lxor:
1742: case opc_i2l:
1743: case opc_i2f:
1744: case opc_i2d:
1745: case opc_l2i:
1746: case opc_l2f:
1747: case opc_l2d:
1748: case opc_f2i:
1749: case opc_f2l:
1750: case opc_f2d:
1751: case opc_d2i:
1752: case opc_d2l:
1753: case opc_d2f:
1754: case opc_i2b:
1755: case opc_i2c:
1756: case opc_i2s:
1757: case opc_lcmp:
1758: case opc_fcmpl:
1759: case opc_fcmpg:
1760: case opc_dcmpl:
1761: case opc_dcmpg:
1762: case opc_ireturn:
1763: case opc_lreturn:
1764: case opc_freturn:
1765: case opc_dreturn:
1766: case opc_areturn:
1767: case opc_return:
1768: case opc_athrow:
1769: case opc_arraylength:
1770: case opc_monitorenter:
1771: case opc_monitorexit:
1772: output.writeByte(opcode);
1773: break;
1774: default:
1775: throw new ClassFormatError("Invalid opcode " + opcode);
1776: }
1777: }
1778:
1779: output.writeShort(exceptionHandlers.length);
1780: for (int i = 0; i < exceptionHandlers.length; i++) {
1781: output.writeShort(exceptionHandlers[i].start.getAddr());
1782: output.writeShort(exceptionHandlers[i].end.getNextByAddr()
1783: .getAddr());
1784: output.writeShort(exceptionHandlers[i].catcher.getAddr());
1785: output.writeShort((exceptionHandlers[i].type == null) ? 0
1786: : gcp.putClassName(exceptionHandlers[i].type));
1787: }
1788: writeAttributes(gcp, output);
1789: }
1790:
1791: public void dropInfo(int howMuch) {
1792: if ((howMuch & KNOWNATTRIBS) != 0) {
1793: lvt = null;
1794: lnt = null;
1795: }
1796: super .dropInfo(howMuch);
1797: }
1798:
1799: public int getSize() {
1800: /* maxStack: 2
1801: * maxLocals: 2
1802: * code: 4 + codeLength
1803: * exc count: 2
1804: * exceptions: n * 8
1805: * attributes:
1806: * lvt_name: 2
1807: * lvt_length: 4
1808: * lvt_count: 2
1809: * lvt_entries: n * 10
1810: * attributes:
1811: * lnt_name: 2
1812: * lnt_length: 4
1813: * lnt_count: 2
1814: * lnt_entries: n * 4
1815: */
1816: int size = 0;
1817: if (lvt != null)
1818: size += 8 + lvt.length * 10;
1819: if (lnt != null)
1820: size += 8 + lnt.length * 4;
1821: return 10 + instructions.getCodeLength()
1822: + exceptionHandlers.length * 8 + getAttributeSize()
1823: + size;
1824: }
1825:
1826: public int getMaxStack() {
1827: return maxStack;
1828: }
1829:
1830: public int getMaxLocals() {
1831: return maxLocals;
1832: }
1833:
1834: public MethodInfo getMethodInfo() {
1835: return methodInfo;
1836: }
1837:
1838: public List getInstructions() {
1839: return instructions;
1840: }
1841:
1842: public Handler[] getExceptionHandlers() {
1843: return exceptionHandlers;
1844: }
1845:
1846: public LocalVariableInfo[] getLocalVariableTable() {
1847: return lvt;
1848: }
1849:
1850: public LineNumber[] getLineNumberTable() {
1851: return lnt;
1852: }
1853:
1854: public void setExceptionHandlers(Handler[] handlers) {
1855: exceptionHandlers = handlers;
1856: }
1857:
1858: public void setLocalVariableTable(LocalVariableInfo[] newLvt) {
1859: lvt = newLvt;
1860: }
1861:
1862: public void setLineNumberTable(LineNumber[] newLnt) {
1863: lnt = newLnt;
1864: }
1865:
1866: public String toString() {
1867: return "Bytecode " + methodInfo;
1868: }
1869: }
|