0001: /*
0002: *
0003: *
0004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package components;
0028:
0029: import java.io.DataInput;
0030: import java.io.DataOutput;
0031: import java.io.IOException;
0032: import java.io.PrintWriter;
0033: import java.io.StringWriter;
0034: import java.util.Hashtable;
0035: import jcc.Const;
0036: import jcc.EVMConst;
0037: import jcc.Util;
0038: import util.DataFormatException;
0039:
0040: // Class for representing every method in a class
0041:
0042: public class MethodInfo extends ClassMemberInfo implements Const {
0043: public int argsSize;
0044: public int stack;
0045: public int locals;
0046: public int methodTableIndex = -1;
0047:
0048: public byte code[];
0049:
0050: private Attribute methodAttributes[];
0051: public CodeAttribute codeAttribute;
0052: public Attribute codeAttributes[];
0053: public ExceptionEntry exceptionTable[];
0054: public ClassConstant exceptionsThrown[];
0055: private boolean checkedDebugTables = false;
0056: private LineNumberTableEntry lineNumberTable[];
0057: private LocalVariableTableEntry localVariableTable[];
0058: public StackMapFrame stackMapTable[];
0059: public vm.VMMethodInfo vmMethodInfo;
0060:
0061: /* An array of the methods called by invokevirtual_quick and
0062: * invokevirtualobject_quick. (After quickening, before inlining).
0063: */
0064: public MethodInfo[] targetMethods;
0065:
0066: /**
0067: * The following are arrays of indexes into the
0068: * code array of references to the constant pool:
0069: * ldcInstructions lists the instructions with a one-byte index.
0070: * wideConstantRefInstructions lists the instructions with a two-byte index.
0071: * In each case, the index is that of the opcode: the actual reference
0072: * begins with the following byte.
0073: * Entries of value -1 are ignored.
0074: */
0075: public int ldcInstructions[];
0076: public int wideConstantRefInstructions[];
0077:
0078: public MethodInfo(int name, int sig, int access, ClassInfo p) {
0079: super (name, sig, access, p);
0080: }
0081:
0082: public void initializeClassDebugTables() {
0083: int nattr = (codeAttributes == null) ? 0
0084: : codeAttributes.length;
0085: // parse code attributes
0086: for (int i = 0; i < nattr; i++) {
0087: Attribute a = codeAttributes[i];
0088: if (a.name.string.equals("LineNumberTable")) {
0089: lineNumberTable = ((LineNumberTableAttribute) a).data;
0090: }
0091: if (a.name.string.equals("LocalVariableTable")) {
0092: localVariableTable = ((LocalVariableTableAttribute) a).data;
0093: }
0094: if (a.name.string.equals("StackMap")) {
0095: stackMapTable = ((StackMapAttribute) a).data;
0096: }
0097:
0098: }
0099: }
0100:
0101: public LineNumberTableEntry[] getLineNumberTable() {
0102: if (!checkedDebugTables) {
0103: initializeClassDebugTables();
0104: checkedDebugTables = true;
0105: }
0106: return lineNumberTable;
0107: }
0108:
0109: public LocalVariableTableEntry[] getLocalVariableTable() {
0110: if (!checkedDebugTables) {
0111: initializeClassDebugTables();
0112: checkedDebugTables = true;
0113: }
0114: return localVariableTable;
0115: }
0116:
0117: public boolean hasLineNumberTable() {
0118: if (!checkedDebugTables) {
0119: initializeClassDebugTables();
0120: checkedDebugTables = true;
0121: }
0122: return (lineNumberTable != null)
0123: && (lineNumberTable.length != 0);
0124: }
0125:
0126: public boolean hasLocalVariableTable() {
0127: if (!checkedDebugTables) {
0128: initializeClassDebugTables();
0129: checkedDebugTables = true;
0130: }
0131: return (localVariableTable != null)
0132: && (localVariableTable.length != 0);
0133: }
0134:
0135: public boolean throwsExceptions() {
0136: return exceptionsThrown != null;
0137: }
0138:
0139: public ClassConstant[] getExceptionsThrown() {
0140: return exceptionsThrown;
0141: }
0142:
0143: public int nExceptionsThrown() {
0144: return (exceptionsThrown == null) ? 0 : exceptionsThrown.length;
0145: }
0146:
0147: private String nativeName;
0148:
0149: public String getNativeName(boolean isJNI) {
0150: if (nativeName == null) {
0151: nativeName = isJNI ? getJNIName() : getOldNativeName();
0152: }
0153: return nativeName;
0154: }
0155:
0156: public String getJNIReturnType() {
0157: return Util.parseReturnType(this .type.string);
0158: }
0159:
0160: private String getJNIName() {
0161: ClassInfo ci = parent;
0162: String classname = ci.className;
0163: String methodname = this .name.string;
0164: int nmethods = ci.methods.length;
0165: String typeName = null; // by default, don't need type
0166: for (int j = 0; j < nmethods; j++) {
0167: MethodInfo m = ci.methods[j];
0168: if ((m != this ) && ((m.access & Const.ACC_NATIVE) != 0)) {
0169: if (m.name.equals(this .name)) {
0170: // Two native methods with the same name. Need type name
0171: typeName = this .type.string;
0172: break;
0173: }
0174: }
0175: }
0176: return Util.convertToJNIName(classname, methodname, typeName);
0177: }
0178:
0179: private String getOldNativeName() {
0180: ClassInfo ci = parent;
0181: String methodname = this .name.string;
0182: StringBuffer sbuf = new StringBuffer(/*NOI18N*/"Java_")
0183: .append(ci.getGenericNativeName()).append('_');
0184: if (methodname.indexOf('_') == -1) {
0185: // optimization. Most methods don't have an _ in them
0186: sbuf.append(methodname);
0187: } else {
0188: for (int i = 0; i < methodname.length(); i++) {
0189: if (methodname.charAt(i) == '_') {
0190: sbuf.append(/*NOI18N*/"_0005f");
0191: } else {
0192: sbuf.append(methodname.charAt(i));
0193: }
0194: }
0195: }
0196: sbuf.append("_stub");
0197: return sbuf.toString();
0198: }
0199:
0200: /*
0201: * A methods attributes are Code and Exceptions.
0202: */
0203: private static Hashtable methodAttributeTypes = new Hashtable();
0204:
0205: static {
0206: methodAttributeTypes.put("Code", CodeAttributeFactory.instance);
0207: methodAttributeTypes.put("Exceptions",
0208: ExceptionsAttributeFactory.instance);
0209: }
0210:
0211: // Read in method attributes from classfile
0212: void readAttributes(DataInput in, ConstantObject locals[],
0213: ConstantObject globals[], boolean readCode)
0214: throws IOException {
0215:
0216: methodAttributes = Attribute.readAttributes(in, locals,
0217: globals, methodAttributeTypes, false);
0218:
0219: // oops, we read the code.
0220: // we'll fix this someday.
0221:
0222: //
0223: // parse special attributes
0224: //
0225: if (methodAttributes != null) {
0226: for (int i = 0; i < methodAttributes.length; i++) {
0227: Attribute a = methodAttributes[i];
0228: if (a.name.string.equals("Code")) {
0229: CodeAttribute ca = (CodeAttribute) a;
0230: this .locals = ca.locals;
0231: this .stack = ca.stack;
0232: this .code = ca.code;
0233: this .exceptionTable = ca.exceptionTable;
0234: this .codeAttributes = ca.codeAttributes;
0235: this .codeAttribute = ca;
0236: } else if (a.name.string.equals("Exceptions")) {
0237: this .exceptionsThrown = ((ExceptionsAttribute) a).data;
0238: }
0239: }
0240: }
0241:
0242: }
0243:
0244: public static MethodInfo readMethod(DataInput in, ClassInfo p,
0245: boolean readCode) throws IOException {
0246: int access = in.readUnsignedShort();
0247: int name = in.readUnsignedShort();
0248: int sig = in.readUnsignedShort();
0249: MethodInfo m = new MethodInfo(name, sig, access, p);
0250: // the bad thing is, we really cannot go far
0251: // without resolving. So we resolve here.
0252: m.resolve(p.symbols);
0253:
0254: m.argsSize = Util.argsSize(m.type.string);
0255: if ((m.access & ACC_STATIC) == 0) {
0256: m.argsSize++;
0257: }
0258:
0259: m.readAttributes(in, p.constants, p.symbols, readCode);
0260: return m;
0261: }
0262:
0263: public void externalize(ConstantPool p) {
0264: super .externalize(p);
0265: Attribute.externalizeAttributes(methodAttributes, p);
0266: Attribute.externalizeAttributes(codeAttributes, p);
0267: }
0268:
0269: public void write(DataOutput o) throws IOException {
0270: o.writeShort(access);
0271: o.writeShort(name.index);
0272: o.writeShort(type.index);
0273: Attribute.writeAttributes(methodAttributes, o, false);
0274: }
0275:
0276: private static int getInt(byte[] code, int w) {
0277: return ((int) code[w] << 24)
0278: | (((int) code[w + 1] & 0xff) << 16)
0279: | (((int) code[w + 2] & 0xff) << 8)
0280: | ((int) code[w + 3] & 0xff);
0281: }
0282:
0283: public int getInt(int w) {
0284: return getInt(code, w);
0285: }
0286:
0287: public int getUnsignedShort(int w) {
0288: return (((int) code[w] & 0xff) << 8)
0289: | ((int) code[w + 1] & 0xff);
0290: }
0291:
0292: public int getShort(int w) {
0293: return (((int) code[w]) << 8) | ((int) code[w + 1] & 0xff);
0294: }
0295:
0296: //
0297: // Private Utility functions
0298: private void putInt(byte array[], int offset, int val) {
0299: array[offset] = (byte) ((val >> 24) & 0xFF);
0300: array[offset + 1] = (byte) ((val >> 16) & 0xFF);
0301: array[offset + 2] = (byte) ((val >> 8) & 0xFF);
0302: array[offset + 3] = (byte) (val & 0xFF);
0303: }
0304:
0305: private void putShort(int w, short v) {
0306: code[w] = (byte) (v >>> 8);
0307: code[w + 1] = (byte) v;
0308: }
0309:
0310: public void findConstantReferences() throws DataFormatException {
0311: if (code == null)
0312: return; // no code, no references.
0313: int ldc[] = new int[code.length / 2];
0314: int wide[] = new int[code.length / 3];
0315: int nldc = 0;
0316: int nwide = 0;
0317: int ncode = code.length;
0318: int opcode;
0319: for (int i = 0; i < ncode; /*nothing*/) {
0320: switch (opcode = (int) code[i] & 0xff) {
0321: case opc_tableswitch:
0322: i = (i + 4) & ~3;
0323: int low = getInt(i + 4);
0324: int high = getInt(i + 8);
0325: i += (high - low + 1) * 4 + 12;
0326: break;
0327:
0328: case opc_lookupswitch:
0329: i = (i + 4) & ~3;
0330: int pairs = getInt(i + 4);
0331: i += pairs * 8 + 8;
0332: break;
0333:
0334: case opc_wide:
0335: switch ((int) code[i + 1] & 0xff) {
0336: case opc_aload:
0337: case opc_iload:
0338: case opc_fload:
0339: case opc_lload:
0340: case opc_dload:
0341: case opc_istore:
0342: case opc_astore:
0343: case opc_fstore:
0344: case opc_lstore:
0345: case opc_dstore:
0346: case opc_ret:
0347: i += 4;
0348: break;
0349:
0350: case opc_iinc:
0351: i += 6;
0352: break;
0353:
0354: default:
0355: throw new DataFormatException(parent.className
0356: + "." + name.string + ": unknown wide "
0357: + "instruction: " + code[i + 1]);
0358: }
0359: break;
0360: case opc_ldc:
0361: ldc[nldc++] = i;
0362: i += opcLengths[opcode];
0363: break;
0364: case opc_ldc_w:
0365: case opc_ldc2_w:
0366: case opc_getstatic:
0367: case opc_putstatic:
0368: case opc_getfield:
0369: case opc_putfield:
0370: case opc_invokevirtual:
0371: case opc_invokespecial:
0372: case opc_invokestatic:
0373: case opc_invokeinterface:
0374: case opc_new:
0375: case opc_anewarray:
0376: case opc_checkcast:
0377: case opc_instanceof :
0378: case opc_multianewarray:
0379:
0380: case opc_getstatic_fast:
0381: case opc_getstaticp_fast:
0382: case opc_getstatic2_fast:
0383: case opc_putstatic_fast:
0384: case opc_putstatic2_fast:
0385: case opc_invokevirtual_fast:
0386: case opc_invokespecial_fast:
0387: case opc_invokestatic_fast:
0388: case opc_invokeinterface_fast:
0389: case opc_new_fast:
0390: case opc_anewarray_fast:
0391: case opc_multianewarray_fast:
0392: case opc_checkcast_fast:
0393: case opc_instanceof _fast:
0394: wide[nwide++] = i;
0395: i += opcLengths[opcode];
0396: break;
0397: default:
0398: i += opcLengths[opcode];
0399: break;
0400: }
0401: }
0402: // not knowing any better, we allocated excess capacity.
0403: // allocate and fill appropriately-sized arrays.
0404: ldcInstructions = new int[nldc];
0405: System.arraycopy(ldc, 0, ldcInstructions, 0, nldc);
0406: ldc = null;
0407: wideConstantRefInstructions = new int[nwide];
0408: System
0409: .arraycopy(wide, 0, wideConstantRefInstructions, 0,
0410: nwide);
0411: wide = null;
0412: }
0413:
0414: private static int opcodeLength(byte[] code, int pc) {
0415: int old_pc;
0416: int opcode = (int) code[pc] & 0xff;
0417: switch (opcode) {
0418:
0419: case opc_tableswitch:
0420: old_pc = pc;
0421: pc = (pc + 4) & ~3;
0422: int low = getInt(code, pc + 4);
0423: int high = getInt(code, pc + 8);
0424: pc += (high - low + 1) * 4 + 12;
0425: return pc - old_pc;
0426:
0427: case opc_lookupswitch:
0428: old_pc = pc;
0429: pc = (pc + 4) & ~3;
0430: int pairs = getInt(code, pc + 4);
0431: pc += pairs * 8 + 8;
0432: return pc - old_pc;
0433:
0434: case opc_wide:
0435: if (((int) code[pc + 1] & 0xff) == opc_iinc)
0436: return 6;
0437: return 4;
0438:
0439: default:
0440: return opcLengths[opcode];
0441: }
0442: }
0443:
0444: public int opcodeLength(int pc) {
0445: return opcodeLength(code, pc);
0446: }
0447:
0448: public void countConstantReferences(ConstantObject table[],
0449: boolean isRelocatable) {
0450: super .countConstantReferences();
0451: Attribute.countConstantReferences(methodAttributes,
0452: isRelocatable);
0453: Attribute
0454: .countConstantReferences(codeAttributes, isRelocatable);
0455: if (code == null)
0456: return; // no code, no relocation
0457: if (ldcInstructions != null) {
0458: int list[] = ldcInstructions;
0459: int n = list.length;
0460: for (int i = 0; i < n; i++) {
0461: int loc = list[i];
0462: if (loc == -1)
0463: continue;
0464: table[(int) code[loc + 1] & 0xff].incReference();
0465: }
0466: }
0467: if (wideConstantRefInstructions != null) {
0468: int list[] = wideConstantRefInstructions;
0469: int n = list.length;
0470: for (int i = 0; i < n; i++) {
0471: int loc = list[i];
0472: if (loc == -1)
0473: continue;
0474: table[getUnsignedShort(loc + 1)].incReference();
0475: }
0476: }
0477: }
0478:
0479: public void relocateConstantReferences(ConstantObject table[])
0480: throws DataFormatException {
0481: if (code == null)
0482: return; // no code, no relocation
0483: if (ldcInstructions != null) {
0484: int list[] = ldcInstructions;
0485: int n = list.length;
0486: for (int i = 0; i < n; i++) {
0487: int j = list[i] + 1;
0488: if (j <= 0)
0489: continue;
0490: ConstantObject c = table[(int) code[j] & 0xff];
0491: if (c.shared)
0492: throw new DataFormatException(
0493: "code reference to shared constant");
0494: int v = c.index;
0495: if (v < 0)
0496: throw new DataFormatException(
0497: "code reference to deleted constant at "
0498: + qualifiedName() + "+"
0499: + Integer.toHexString(j));
0500: if (v > 255)
0501: throw new DataFormatException(
0502: "ldc subscript out of range at "
0503: + qualifiedName() + "+"
0504: + Integer.toHexString(j));
0505: code[j] = (byte) v;
0506: }
0507: }
0508: if (wideConstantRefInstructions != null) {
0509: int list[] = wideConstantRefInstructions;
0510: int n = list.length;
0511: for (int i = 0; i < n; i++) {
0512: int j = list[i] + 1;
0513: if (j <= 0)
0514: continue;
0515: ConstantObject c = table[getUnsignedShort(j)];
0516: if (c.shared)
0517: throw new DataFormatException(
0518: "code reference to shared constant at "
0519: + qualifiedName() + "+"
0520: + Integer.toHexString(j));
0521: int v = c.index;
0522: if (v < 0)
0523: throw new DataFormatException(
0524: "code reference to deleted constant at "
0525: + qualifiedName() + "+"
0526: + Integer.toHexString(j));
0527: putShort(j, (short) v);
0528: }
0529: }
0530: }
0531:
0532: public void replaceCode(int start, int end) {
0533: replaceCode(start, end, new byte[0]);
0534: }
0535:
0536: public void replaceCode(int start, int end, int op1) {
0537: byte code[] = { (byte) op1 };
0538: replaceCode(start, end, code);
0539: }
0540:
0541: public void replaceCode(int start, int end, int op1, int op2) {
0542: byte code[] = { (byte) op1, (byte) op2 };
0543: replaceCode(start, end, code);
0544: }
0545:
0546: public void replaceCode(int start, int end, int op1, int op2,
0547: int op3) {
0548: byte code[] = { (byte) op1, (byte) op2, (byte) op3 };
0549: replaceCode(start, end, code);
0550: }
0551:
0552: public java.util.BitSet getLabelTargets() {
0553: java.util.BitSet result = new java.util.BitSet();
0554: int ncode = code.length;
0555: int nextpc;
0556:
0557: for (int pc = 0; pc < ncode; pc = nextpc) {
0558: nextpc = pc + opcodeLength(pc);
0559: int opcode = (int) code[pc] & 0xff;
0560: switch (opcode) {
0561:
0562: case opc_tableswitch:
0563: case opc_lookupswitch:
0564: int i = (pc + 4) & ~3;
0565: int delta = (opcode == opc_tableswitch) ? 4 : 8;
0566: result.set(pc + getInt(i)); // default
0567: for (i = i + 12; i < nextpc; i += delta)
0568: result.set(pc + getInt(i));
0569: break;
0570:
0571: case opc_jsr:
0572: result.set(pc + 3);
0573: case opc_goto:
0574: case opc_ifeq:
0575: case opc_ifge:
0576: case opc_ifgt:
0577: case opc_ifle:
0578: case opc_iflt:
0579: case opc_ifne:
0580: case opc_if_icmpeq:
0581: case opc_if_icmpne:
0582: case opc_if_icmpge:
0583: case opc_if_icmplt:
0584: case opc_if_icmpgt:
0585: case opc_if_icmple:
0586: case opc_if_acmpeq:
0587: case opc_if_acmpne:
0588: case opc_ifnull:
0589: case opc_ifnonnull:
0590: result.set(pc + getShort(pc + 1));
0591: break;
0592:
0593: case opc_jsr_w:
0594: result.set(pc + 5);
0595: case opc_goto_w:
0596: result.set(pc + getInt(pc + 1));
0597: break;
0598: }
0599: }
0600: return result;
0601: }
0602:
0603: public void replaceCode(int start, int end, byte[] replaceCode) {
0604: if (end - start < replaceCode.length) {
0605: // System.out.println(" Cannot yet do expansion!!");
0606: return;
0607: }
0608: if (exceptionTable != null && exceptionTable.length > 0) {
0609: for (int i = 0; i < exceptionTable.length; i++) {
0610: int startPC = exceptionTable[i].startPC;
0611: int endPC = exceptionTable[i].endPC;
0612: if (startPC >= start && startPC < end)
0613: return;
0614: if (endPC >= start && endPC < end)
0615: return;
0616: }
0617: }
0618: int startExtra = start + replaceCode.length;
0619: int extra = end - startExtra;
0620:
0621: System.arraycopy(replaceCode, 0, code, start,
0622: replaceCode.length);
0623:
0624: for (int i = startExtra; i < end; i++)
0625: code[i] = (byte) opc_nop;
0626: }
0627:
0628: public void disassemble() {
0629: System.out.println(disassemble(code, 0, code.length));
0630: }
0631:
0632: public String disassemble(int start, int end) {
0633: return disassemble(code, start, end);
0634: }
0635:
0636: /**
0637: * Return the byte stored at a given index from the offset
0638: * within code bytes
0639: */
0640: private static final int at(byte codeBytes[], int index) {
0641: return codeBytes[index] & 0xFF;
0642: }
0643:
0644: /**
0645: * Return the short stored at a given index from the offset
0646: * within code bytes
0647: */
0648: private static final int shortAt(byte codeBytes[], int index) {
0649: return ((codeBytes[index] & 0xFF) << 8)
0650: | (codeBytes[index + 1] & 0xFF);
0651: }
0652:
0653: public static String disassemble(byte[] codeBytes, int start,
0654: int end) {
0655: // Output goes into a string
0656: StringWriter sw = new StringWriter();
0657: PrintWriter output = new PrintWriter(sw);
0658:
0659: for (int offset = start; offset < end;) {
0660: int opcode = at(codeBytes, offset);
0661:
0662: if (offset > start)
0663: output.print("; ");
0664:
0665: output.print(opcodeName(opcode));
0666:
0667: switch (opcode) {
0668: case opc_aload:
0669: case opc_astore:
0670: case opc_fload:
0671: case opc_fstore:
0672: case opc_iload:
0673: case opc_istore:
0674: case opc_lload:
0675: case opc_lstore:
0676: case opc_dload:
0677: case opc_dstore:
0678: case opc_ret:
0679: output.print(" " + at(codeBytes, offset + 1));
0680: offset += 2;
0681: break;
0682:
0683: case opc_iinc:
0684: output.print(" " + at(codeBytes, offset + 1) + " "
0685: + (byte) at(codeBytes, offset + 2));
0686: offset += 3;
0687: break;
0688:
0689: case opc_newarray:
0690: switch (at(codeBytes, offset + 1)) {
0691: case T_INT:
0692: output.print(" int");
0693: break;
0694: case T_LONG:
0695: output.print(" long");
0696: break;
0697: case T_FLOAT:
0698: output.print(" float");
0699: break;
0700: case T_DOUBLE:
0701: output.print(" double");
0702: break;
0703: case T_CHAR:
0704: output.print(" char");
0705: break;
0706: case T_SHORT:
0707: output.print(" short");
0708: break;
0709: case T_BYTE:
0710: output.print(" byte");
0711: break;
0712: case T_BOOLEAN:
0713: output.print(" boolean");
0714: break;
0715: default:
0716: output.print(" BOGUS");
0717: break;
0718: }
0719: offset += 2;
0720: break;
0721:
0722: case opc_anewarray_fast:
0723: case opc_anewarray: {
0724: int index = shortAt(codeBytes, offset + 1);
0725: output.print(" class #" + index + " ");
0726: offset += 3;
0727: break;
0728: }
0729:
0730: case opc_sipush:
0731: output.print(" "
0732: + (short) shortAt(codeBytes, offset + 1));
0733: offset += 3;
0734: break;
0735:
0736: case opc_bipush:
0737: output.print(" " + (byte) at(codeBytes, offset + 1));
0738: offset += 2;
0739: break;
0740:
0741: case opc_ldc: {
0742: int index = at(codeBytes, offset + 1);
0743: output.print(" #" + index + " ");
0744: offset += 2;
0745: break;
0746: }
0747:
0748: case opc_getstatic_fast:
0749: case opc_getstaticp_fast:
0750: case opc_getstatic2_fast:
0751: case opc_putstatic_fast:
0752: case opc_putstatic2_fast:
0753: case opc_unused_d5:
0754: case opc_invokevirtual_fast:
0755: case opc_invokespecial_fast:
0756: case opc_invokestatic_fast:
0757: case opc_invokeinterface_fast:
0758: case opc_new_fast:
0759: case opc_multianewarray_fast:
0760: case opc_checkcast_fast:
0761: case opc_instanceof _fast:
0762: case opc_ldc_w:
0763: case opc_ldc2_w:
0764: case opc_instanceof :
0765: case opc_checkcast:
0766: case opc_new:
0767: case opc_putstatic:
0768: case opc_getstatic:
0769: case opc_putfield:
0770: case opc_getfield:
0771: case opc_invokevirtual:
0772: case opc_invokespecial:
0773: case opc_invokestatic: {
0774: int index = shortAt(codeBytes, offset + 1);
0775: output.print(" #" + index + " ");
0776: offset += 3;
0777: break;
0778: }
0779:
0780: case opc_getfield_fast:
0781: case opc_getfieldp_fast:
0782: case opc_getfield2_fast:
0783: case opc_putfield_fast:
0784: case opc_putfield2_fast: {
0785: int index = at(codeBytes, offset + 1);
0786: output.print(" [" + index + "] ");
0787: offset += 3;
0788: break;
0789: }
0790:
0791: case opc_jsr:
0792: case opc_goto:
0793: case opc_ifeq:
0794: case opc_ifge:
0795: case opc_ifgt:
0796: case opc_ifle:
0797: case opc_iflt:
0798: case opc_ifne:
0799: case opc_if_icmpeq:
0800: case opc_if_icmpne:
0801: case opc_if_icmpge:
0802: case opc_if_icmpgt:
0803: case opc_if_icmple:
0804: case opc_if_icmplt:
0805: case opc_if_acmpeq:
0806: case opc_if_acmpne:
0807: case opc_ifnull:
0808: case opc_ifnonnull: {
0809: int target = offset
0810: + (short) shortAt(codeBytes, offset + 1);
0811: output.print(" " + target);
0812: offset += 3;
0813: break;
0814: }
0815:
0816: default:
0817: offset += opcodeLength(codeBytes, offset);
0818: break;
0819: }
0820: }
0821:
0822: output.close();
0823: return sw.toString();
0824: }
0825:
0826: public static String opcodeName(int opcode) {
0827: return opcNames[opcode];
0828: }
0829:
0830: public String toString() {
0831: String r = "Method: " + super .toString();
0832: if (code != null) {
0833: r += " {" + code.length + " bytes of code}";
0834: }
0835: return r;
0836: }
0837:
0838: // Case 1: expand code.
0839: // Convert ldc to ldc2: a. Insert extra bytes
0840: // b. Fix all branch targets/exception ranges
0841: // Case 2: smash code
0842: // ldc_w_fast has index which is less than 255. Change to use
0843: // ldc_w.
0844: public void relocateAndPackCode(ConstantObject co[]) {
0845:
0846: if (code == null)
0847: return;
0848:
0849: int opcode, adjustment = 0;
0850: int newOffsets[] = new int[code.length];
0851: int indexByPC[] = new int[code.length];
0852:
0853: // First figure out where we'll have to insert extra bytes in
0854: // order to fit opc_ldc_w instead of opc_ldc instructions.
0855: for (int pc = 0, pcindex = 0; pc < code.length; pc = pc
0856: + opcodeLength(pc), pcindex++) {
0857: opcode = (int) code[pc] & 0xFF;
0858: newOffsets[pcindex] = pc + adjustment;
0859: indexByPC[pc] = pcindex;
0860:
0861: /*******
0862: * switch (opcode) {
0863: * case opc_ldc: {
0864: * // a conversion table which maps pcValue to new index.
0865: * int oldindex = (int)(code[pc+1] & 0xFF);
0866: * int index = co[oldindex].index;
0867: *
0868: * if (index >= 0x100)
0869: * adjustment++;
0870: * break;
0871: * }
0872: *
0873: *
0874: * case opc_ldc_w: {
0875: * // a conversion table which maps pcValue to new index.
0876: * int oldindex = (int)(((code[pc+1]&0xFF) << 8)
0877: * | (code[pc+2]&0xFF));
0878: * int index = co[oldindex].index;
0879: *
0880: * if (index < 0x100)
0881: * adjustment--;
0882: * break;
0883: * }
0884: *
0885: *
0886: *
0887: * case opc_goto: {
0888: * // Calculate the displacement, sign extend high byte
0889: * int displ = (code[pc+1] << 8) | (code[pc+2] & 0xFF);
0890: *
0891: * if (displ == 3) {
0892: * adjustment -= 3; // remove no-use goto's.
0893: * }
0894: * break;
0895: * }
0896: *
0897: * case opc_nop: {
0898: * adjustment--; // remove
0899: * break;
0900: * }
0901: *
0902: *
0903: * case opc_tableswitch:
0904: * case opc_lookupswitch: {
0905: * int oldExtraPC = (( pc + 4 ) & ~3);
0906: * int newExtraPC = (( pc + adjustment + 4) & ~3);
0907: * adjustment = newExtraPC - oldExtraPC;
0908: * break;
0909: * }
0910: * }
0911: *******/
0912: }
0913:
0914: // Now copy the code to the new location. At the same
0915: // time, we adjust all branch targets.
0916: byte newCode[] = new byte[code.length + adjustment];
0917:
0918: for (int pc = 0, pcindex = 0; pc < code.length; pc = pc
0919: + opcodeLength(pc), pcindex++) {
0920: int outPos = newOffsets[pcindex];
0921: int inPos = pc;
0922:
0923: opcode = (int) code[pc] & 0xFF;
0924:
0925: for (int i = 0; i < opcodeLength(pc); i++) {
0926: newCode[outPos + i] = code[pc + i];
0927: }
0928:
0929: switch (opcode) {
0930: case opc_ldc: {
0931: int oldindex = (int) (code[pc + 1] & 0xFF);
0932: int index = co[oldindex].index;
0933: if (index >= 0x100) {
0934: new RuntimeException("load constant overflow");
0935: }
0936: newCode[outPos + 1] = (byte) index;
0937: break;
0938: }
0939:
0940: /****
0941: * // Remapping branches
0942: * case opc_ifeq:
0943: * case opc_ifne:
0944: * case opc_iflt:
0945: * case opc_ifge:
0946: * case opc_ifgt:
0947: * case opc_ifle:
0948: * case opc_if_icmpeq:
0949: * case opc_if_icmpne:
0950: * case opc_if_icmplt:
0951: * case opc_if_icmpge:
0952: * case opc_if_icmpgt:
0953: * case opc_if_icmple:
0954: * case opc_if_acmpeq:
0955: * case opc_if_acmpne:
0956: * case opc_ifnull:
0957: * case opc_ifnonnull:
0958: * case opc_goto:
0959: * case opc_jsr: {
0960: * // Calculate the displacement, sign extend high byte
0961: * int displ = (code[pc+1] << 8) | (code[pc+2] & 0xFF);
0962: *
0963: * * if (displ == 3 && opcode == opc_goto) {
0964: * * break;
0965: * * }
0966: *
0967:
0968: * int branchDest = pc + displ;
0969: *
0970: * if ((code[branchDest] & 0xFF) == opc_goto) {
0971: * // We're branching to a goto. We can just branch to
0972: * // where the goto was going.
0973: * branchDest +=
0974: * (code[branchDest+1] << 8) | (code[branchDest+2] & 0xFF);
0975: * }
0976: * int newDest = newOffsets[indexByPC[branchDest]] - outPos;
0977: * newCode[outPos+1] = (byte) ((newDest >> 8) & 0xFF);
0978: * newCode[outPos+2] = (byte) (newDest & 0xFF);
0979: * break;
0980: * }
0981: *
0982: * case opc_tableswitch: {
0983: * newCode[outPos] = code[pc];
0984: * outPos = (outPos + 4) & ~3;
0985: * inPos = (inPos + 4) & ~3;
0986: *
0987: * // Update the default destination
0988: * int oldDest = getInt(inPos) + pc;
0989: * int newDest = newOffsets[indexByPC[oldDest]]
0990: * - newOffsets[pcindex];
0991: * putInt(newCode, outPos, newDest);
0992: *
0993: * // Update each of the destinations in the table
0994: * int low = getInt(inPos+4);
0995: * int high = getInt(inPos+8);
0996: * putInt(newCode, outPos+4, low);
0997: * putInt(newCode, outPos+8, high);
0998: * for (int j = 0; j <= high-low; j++) {
0999: * int offset = j * 4 + 12;
1000: * oldDest = getInt(inPos + offset) + pc;
1001: * newDest = newOffsets[indexByPC[oldDest]]
1002: * - newOffsets[pcindex];
1003: * putInt(newCode, outPos + offset, newDest);
1004: * }
1005: * break;
1006: * }
1007: *
1008: * case opc_lookupswitch: {
1009: * newCode[outPos] = code[pc];
1010: * // 0-3 byte pads
1011: * outPos = (outPos + 4) & ~3;
1012: * inPos = (inPos + 4) & ~3;
1013: *
1014: * // Update the default destination
1015: * int oldDest = getInt(inPos) + pc;
1016: * int newDest = newOffsets[indexByPC[oldDest]]
1017: * - newOffsets[pcindex];
1018: * putInt(newCode, outPos, newDest);
1019: *
1020: * // Update each of the pairs of destinations in the list
1021: * int pairs = getInt(inPos+4);
1022: * putInt(newCode, outPos+4, pairs);
1023: * for (int j = 0; j < pairs; j++) {
1024: * int offset = (j + 1) * 8;
1025: *
1026: * // First copy the value
1027: * putInt(newCode, outPos + offset,
1028: * getInt(inPos + offset));
1029: * offset += 4;
1030: *
1031: * // Now adjust the destination
1032: * oldDest = getInt(inPos + offset) + pc;
1033: * newDest = newOffsets[indexByPC[oldDest]]
1034: * - newOffsets[pcindex];
1035: * putInt(newCode, outPos + offset, newDest);
1036: * }
1037: * break;
1038: * }
1039: ********/
1040:
1041: // Byte-codes with constant pool access. Remap to new indices
1042: case opc_getfield:
1043: case opc_checkcast:
1044: case opc_getstatic:
1045: case opc_instanceof :
1046: case opc_ldc2_w:
1047: case opc_new:
1048: case opc_putfield:
1049: case opc_putstatic:
1050: case opc_invokevirtual:
1051: case opc_invokestatic:
1052: case opc_invokespecial:
1053: case opc_getstatic_fast:
1054: case opc_getstaticp_fast:
1055: case opc_getstatic2_fast:
1056: case opc_putstatic_fast:
1057: case opc_putstatic2_fast:
1058: case opc_invokevirtual_fast:
1059: case opc_invokespecial_fast:
1060: case opc_invokestatic_fast:
1061: case opc_anewarray_fast:
1062: case opc_checkcast_fast:
1063: case opc_instanceof _fast:
1064: case opc_multianewarray:
1065: case opc_multianewarray_fast:
1066: case opc_invokeinterface:
1067: case opc_invokeinterface_fast:
1068: case opc_ldc_w: {
1069: int oldindex = (int) (((code[pc + 1] & 0xFF) << 8) | (code[pc + 2] & 0xFF));
1070: int index = co[oldindex].index;
1071: newCode[outPos] = (byte) opcode;
1072: newCode[outPos + 1] = (byte) ((index >> 8) & 0xFF);
1073: newCode[outPos + 2] = (byte) (index & 0xFF);
1074: break;
1075: }
1076: }
1077: }
1078:
1079: // Update the exception table
1080: for (int i = 0; i < exceptionTable.length; i++) {
1081: ExceptionEntry e = exceptionTable[i];
1082: e.startPC = newOffsets[indexByPC[e.startPC]];
1083: e.endPC = newOffsets[indexByPC[e.endPC]];
1084: e.handlerPC = newOffsets[indexByPC[e.handlerPC]];
1085: }
1086:
1087: // Update the line number table
1088: LineNumberTableEntry[] lntab = getLineNumberTable();
1089: if (lntab != null) {
1090: for (int i = 0; i < lntab.length; i++) {
1091: LineNumberTableEntry e = lntab[i];
1092: e.startPC = newOffsets[indexByPC[e.startPC]];
1093: }
1094: }
1095:
1096: // Update the line number table
1097: LocalVariableTableEntry[] locvartab = getLocalVariableTable();
1098: if (locvartab != null) {
1099: for (int i = 0; i < locvartab.length; i++) {
1100: LocalVariableTableEntry e = locvartab[i];
1101: e.pc0 = newOffsets[indexByPC[e.pc0]];
1102: }
1103: }
1104:
1105: // Update the stack maps
1106: if (stackMapTable != null) {
1107: for (int i = 0; i < stackMapTable.length; i++) {
1108: StackMapFrame frame = stackMapTable[i];
1109: frame.offset = newOffsets[indexByPC[frame.offset]];
1110: }
1111: }
1112: // make the changes permanent
1113: code = newCode;
1114: }
1115: }
|