0001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
0002: *
0003: * ***** BEGIN LICENSE BLOCK *****
0004: * Version: MPL 1.1/GPL 2.0
0005: *
0006: * The contents of this file are subject to the Mozilla Public License Version
0007: * 1.1 (the "License"); you may not use this file except in compliance with
0008: * the License. You may obtain a copy of the License at
0009: * http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the
0014: * License.
0015: *
0016: * The Original Code is Rhino code, released
0017: * May 6, 1999.
0018: *
0019: * The Initial Developer of the Original Code is
0020: * Netscape Communications Corporation.
0021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
0022: * the Initial Developer. All Rights Reserved.
0023: *
0024: * Contributor(s):
0025: * Roger Lawrence
0026: *
0027: * Alternatively, the contents of this file may be used under the terms of
0028: * the GNU General Public License Version 2 or later (the "GPL"), in which
0029: * case the provisions of the GPL are applicable instead of those above. If
0030: * you wish to allow use of your version of this file only under the terms of
0031: * the GPL and not to allow others to use your version of this file under the
0032: * MPL, indicate your decision by deleting the provisions above and replacing
0033: * them with the notice and other provisions required by the GPL. If you do
0034: * not delete the provisions above, a recipient may use your version of this
0035: * file under either the MPL or the GPL.
0036: *
0037: * ***** END LICENSE BLOCK ***** */
0038:
0039: package org.mozilla.classfile;
0040:
0041: import org.mozilla.javascript.ObjToIntMap;
0042: import org.mozilla.javascript.ObjArray;
0043: import org.mozilla.javascript.UintMap;
0044:
0045: import java.io.*;
0046:
0047: /**
0048: * ClassFileWriter
0049: *
0050: * A ClassFileWriter is used to write a Java class file. Methods are
0051: * provided to create fields and methods, and within methods to write
0052: * Java bytecodes.
0053: *
0054: * @author Roger Lawrence
0055: */
0056: public class ClassFileWriter {
0057:
0058: /**
0059: * Thrown for cases where the error in generating the class file is
0060: * due to a program size constraints rather than a likely bug in the
0061: * compiler.
0062: */
0063: public static class ClassFileFormatException extends
0064: RuntimeException {
0065: ClassFileFormatException(String message) {
0066: super (message);
0067: }
0068: }
0069:
0070: /**
0071: * Construct a ClassFileWriter for a class.
0072: *
0073: * @param className the name of the class to write, including
0074: * full package qualification.
0075: * @param superClassName the name of the superclass of the class
0076: * to write, including full package qualification.
0077: * @param sourceFileName the name of the source file to use for
0078: * producing debug information, or null if debug information
0079: * is not desired
0080: */
0081: public ClassFileWriter(String className, String super ClassName,
0082: String sourceFileName) {
0083: generatedClassName = className;
0084: itsConstantPool = new ConstantPool(this );
0085: itsThisClassIndex = itsConstantPool.addClass(className);
0086: itsSuperClassIndex = itsConstantPool.addClass(super ClassName);
0087: if (sourceFileName != null)
0088: itsSourceFileNameIndex = itsConstantPool
0089: .addUtf8(sourceFileName);
0090: itsFlags = ACC_PUBLIC;
0091: }
0092:
0093: public final String getClassName() {
0094: return generatedClassName;
0095: }
0096:
0097: /**
0098: * Add an interface implemented by this class.
0099: *
0100: * This method may be called multiple times for classes that
0101: * implement multiple interfaces.
0102: *
0103: * @param interfaceName a name of an interface implemented
0104: * by the class being written, including full package
0105: * qualification.
0106: */
0107: public void addInterface(String interfaceName) {
0108: short interfaceIndex = itsConstantPool.addClass(interfaceName);
0109: itsInterfaces.add(new Short(interfaceIndex));
0110: }
0111:
0112: public static final short ACC_PUBLIC = 0x0001,
0113: ACC_PRIVATE = 0x0002, ACC_PROTECTED = 0x0004,
0114: ACC_STATIC = 0x0008, ACC_FINAL = 0x0010,
0115: ACC_SYNCHRONIZED = 0x0020, ACC_VOLATILE = 0x0040,
0116: ACC_TRANSIENT = 0x0080, ACC_NATIVE = 0x0100,
0117: ACC_ABSTRACT = 0x0400;
0118:
0119: /**
0120: * Set the class's flags.
0121: *
0122: * Flags must be a set of the following flags, bitwise or'd
0123: * together:
0124: * ACC_PUBLIC
0125: * ACC_PRIVATE
0126: * ACC_PROTECTED
0127: * ACC_FINAL
0128: * ACC_ABSTRACT
0129: * TODO: check that this is the appropriate set
0130: * @param flags the set of class flags to set
0131: */
0132: public void setFlags(short flags) {
0133: itsFlags = flags;
0134: }
0135:
0136: static String getSlashedForm(String name) {
0137: return name.replace('.', '/');
0138: }
0139:
0140: /**
0141: * Convert Java class name in dot notation into
0142: * "Lname-with-dots-replaced-by-slashes;" form suitable for use as
0143: * JVM type signatures.
0144: */
0145: public static String classNameToSignature(String name) {
0146: int nameLength = name.length();
0147: int colonPos = 1 + nameLength;
0148: char[] buf = new char[colonPos + 1];
0149: buf[0] = 'L';
0150: buf[colonPos] = ';';
0151: name.getChars(0, nameLength, buf, 1);
0152: for (int i = 1; i != colonPos; ++i) {
0153: if (buf[i] == '.') {
0154: buf[i] = '/';
0155: }
0156: }
0157: return new String(buf, 0, colonPos + 1);
0158: }
0159:
0160: /**
0161: * Add a field to the class.
0162: *
0163: * @param fieldName the name of the field
0164: * @param type the type of the field using ...
0165: * @param flags the attributes of the field, such as ACC_PUBLIC, etc.
0166: * bitwise or'd together
0167: */
0168: public void addField(String fieldName, String type, short flags) {
0169: short fieldNameIndex = itsConstantPool.addUtf8(fieldName);
0170: short typeIndex = itsConstantPool.addUtf8(type);
0171: itsFields.add(new ClassFileField(fieldNameIndex, typeIndex,
0172: flags));
0173: }
0174:
0175: /**
0176: * Add a field to the class.
0177: *
0178: * @param fieldName the name of the field
0179: * @param type the type of the field using ...
0180: * @param flags the attributes of the field, such as ACC_PUBLIC, etc.
0181: * bitwise or'd together
0182: * @param value an initial integral value
0183: */
0184: public void addField(String fieldName, String type, short flags,
0185: int value) {
0186: short fieldNameIndex = itsConstantPool.addUtf8(fieldName);
0187: short typeIndex = itsConstantPool.addUtf8(type);
0188: ClassFileField field = new ClassFileField(fieldNameIndex,
0189: typeIndex, flags);
0190: field.setAttributes(itsConstantPool.addUtf8("ConstantValue"),
0191: (short) 0, (short) 0, itsConstantPool
0192: .addConstant(value));
0193: itsFields.add(field);
0194: }
0195:
0196: /**
0197: * Add a field to the class.
0198: *
0199: * @param fieldName the name of the field
0200: * @param type the type of the field using ...
0201: * @param flags the attributes of the field, such as ACC_PUBLIC, etc.
0202: * bitwise or'd together
0203: * @param value an initial long value
0204: */
0205: public void addField(String fieldName, String type, short flags,
0206: long value) {
0207: short fieldNameIndex = itsConstantPool.addUtf8(fieldName);
0208: short typeIndex = itsConstantPool.addUtf8(type);
0209: ClassFileField field = new ClassFileField(fieldNameIndex,
0210: typeIndex, flags);
0211: field.setAttributes(itsConstantPool.addUtf8("ConstantValue"),
0212: (short) 0, (short) 2, itsConstantPool
0213: .addConstant(value));
0214: itsFields.add(field);
0215: }
0216:
0217: /**
0218: * Add a field to the class.
0219: *
0220: * @param fieldName the name of the field
0221: * @param type the type of the field using ...
0222: * @param flags the attributes of the field, such as ACC_PUBLIC, etc.
0223: * bitwise or'd together
0224: * @param value an initial double value
0225: */
0226: public void addField(String fieldName, String type, short flags,
0227: double value) {
0228: short fieldNameIndex = itsConstantPool.addUtf8(fieldName);
0229: short typeIndex = itsConstantPool.addUtf8(type);
0230: ClassFileField field = new ClassFileField(fieldNameIndex,
0231: typeIndex, flags);
0232: field.setAttributes(itsConstantPool.addUtf8("ConstantValue"),
0233: (short) 0, (short) 2, itsConstantPool
0234: .addConstant(value));
0235: itsFields.add(field);
0236: }
0237:
0238: /**
0239: * Add Information about java variable to use when generating the local
0240: * variable table.
0241: *
0242: * @param name variable name.
0243: * @param type variable type as bytecode descriptor string.
0244: * @param startPC the starting bytecode PC where this variable is live,
0245: * or -1 if it does not have a Java register.
0246: * @param register the Java register number of variable
0247: * or -1 if it does not have a Java register.
0248: */
0249: public void addVariableDescriptor(String name, String type,
0250: int startPC, int register) {
0251: int nameIndex = itsConstantPool.addUtf8(name);
0252: int descriptorIndex = itsConstantPool.addUtf8(type);
0253: int[] chunk = { nameIndex, descriptorIndex, startPC, register };
0254: if (itsVarDescriptors == null) {
0255: itsVarDescriptors = new ObjArray();
0256: }
0257: itsVarDescriptors.add(chunk);
0258: }
0259:
0260: /**
0261: * Add a method and begin adding code.
0262: *
0263: * This method must be called before other methods for adding code,
0264: * exception tables, etc. can be invoked.
0265: *
0266: * @param methodName the name of the method
0267: * @param type a string representing the type
0268: * @param flags the attributes of the field, such as ACC_PUBLIC, etc.
0269: * bitwise or'd together
0270: */
0271: public void startMethod(String methodName, String type, short flags) {
0272: short methodNameIndex = itsConstantPool.addUtf8(methodName);
0273: short typeIndex = itsConstantPool.addUtf8(type);
0274: itsCurrentMethod = new ClassFileMethod(methodNameIndex,
0275: typeIndex, flags);
0276: itsMethods.add(itsCurrentMethod);
0277: }
0278:
0279: /**
0280: * Complete generation of the method.
0281: *
0282: * After this method is called, no more code can be added to the
0283: * method begun with <code>startMethod</code>.
0284: *
0285: * @param maxLocals the maximum number of local variable slots
0286: * (a.k.a. Java registers) used by the method
0287: */
0288: public void stopMethod(short maxLocals) {
0289: if (itsCurrentMethod == null)
0290: throw new IllegalStateException("No method to stop");
0291:
0292: fixLabelGotos();
0293:
0294: itsMaxLocals = maxLocals;
0295:
0296: int lineNumberTableLength = 0;
0297: if (itsLineNumberTable != null) {
0298: // 6 bytes for the attribute header
0299: // 2 bytes for the line number count
0300: // 4 bytes for each entry
0301: lineNumberTableLength = 6 + 2 + (itsLineNumberTableTop * 4);
0302: }
0303:
0304: int variableTableLength = 0;
0305: if (itsVarDescriptors != null) {
0306: // 6 bytes for the attribute header
0307: // 2 bytes for the variable count
0308: // 10 bytes for each entry
0309: variableTableLength = 6 + 2 + (itsVarDescriptors.size() * 10);
0310: }
0311:
0312: int attrLength = 2 + // attribute_name_index
0313: 4 + // attribute_length
0314: 2 + // max_stack
0315: 2 + // max_locals
0316: 4 + // code_length
0317: itsCodeBufferTop + 2 + // exception_table_length
0318: (itsExceptionTableTop * 8) + 2 + // attributes_count
0319: lineNumberTableLength + variableTableLength;
0320:
0321: if (attrLength > 65536) {
0322: // See http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html,
0323: // section 4.10, "The amount of code per non-native, non-abstract
0324: // method is limited to 65536 bytes...
0325: throw new ClassFileFormatException(
0326: "generated bytecode for method exceeds 64K limit.");
0327: }
0328: byte[] codeAttribute = new byte[attrLength];
0329: int index = 0;
0330: int codeAttrIndex = itsConstantPool.addUtf8("Code");
0331: index = putInt16(codeAttrIndex, codeAttribute, index);
0332: attrLength -= 6; // discount the attribute header
0333: index = putInt32(attrLength, codeAttribute, index);
0334: index = putInt16(itsMaxStack, codeAttribute, index);
0335: index = putInt16(itsMaxLocals, codeAttribute, index);
0336: index = putInt32(itsCodeBufferTop, codeAttribute, index);
0337: System.arraycopy(itsCodeBuffer, 0, codeAttribute, index,
0338: itsCodeBufferTop);
0339: index += itsCodeBufferTop;
0340:
0341: if (itsExceptionTableTop > 0) {
0342: index = putInt16(itsExceptionTableTop, codeAttribute, index);
0343: for (int i = 0; i < itsExceptionTableTop; i++) {
0344: ExceptionTableEntry ete = itsExceptionTable[i];
0345: short startPC = (short) getLabelPC(ete.itsStartLabel);
0346: short endPC = (short) getLabelPC(ete.itsEndLabel);
0347: short handlerPC = (short) getLabelPC(ete.itsHandlerLabel);
0348: short catchType = ete.itsCatchType;
0349: if (startPC == -1)
0350: throw new IllegalStateException(
0351: "start label not defined");
0352: if (endPC == -1)
0353: throw new IllegalStateException(
0354: "end label not defined");
0355: if (handlerPC == -1)
0356: throw new IllegalStateException(
0357: "handler label not defined");
0358:
0359: index = putInt16(startPC, codeAttribute, index);
0360: index = putInt16(endPC, codeAttribute, index);
0361: index = putInt16(handlerPC, codeAttribute, index);
0362: index = putInt16(catchType, codeAttribute, index);
0363: }
0364: } else {
0365: // write 0 as exception table length
0366: index = putInt16(0, codeAttribute, index);
0367: }
0368:
0369: int attributeCount = 0;
0370: if (itsLineNumberTable != null)
0371: attributeCount++;
0372: if (itsVarDescriptors != null)
0373: attributeCount++;
0374: index = putInt16(attributeCount, codeAttribute, index);
0375:
0376: if (itsLineNumberTable != null) {
0377: int lineNumberTableAttrIndex = itsConstantPool
0378: .addUtf8("LineNumberTable");
0379: index = putInt16(lineNumberTableAttrIndex, codeAttribute,
0380: index);
0381: int tableAttrLength = 2 + (itsLineNumberTableTop * 4);
0382: index = putInt32(tableAttrLength, codeAttribute, index);
0383: index = putInt16(itsLineNumberTableTop, codeAttribute,
0384: index);
0385: for (int i = 0; i < itsLineNumberTableTop; i++) {
0386: index = putInt32(itsLineNumberTable[i], codeAttribute,
0387: index);
0388: }
0389: }
0390:
0391: if (itsVarDescriptors != null) {
0392: int variableTableAttrIndex = itsConstantPool
0393: .addUtf8("LocalVariableTable");
0394: index = putInt16(variableTableAttrIndex, codeAttribute,
0395: index);
0396: int varCount = itsVarDescriptors.size();
0397: int tableAttrLength = 2 + (varCount * 10);
0398: index = putInt32(tableAttrLength, codeAttribute, index);
0399: index = putInt16(varCount, codeAttribute, index);
0400: for (int i = 0; i < varCount; i++) {
0401: int[] chunk = (int[]) itsVarDescriptors.get(i);
0402: int nameIndex = chunk[0];
0403: int descriptorIndex = chunk[1];
0404: int startPC = chunk[2];
0405: int register = chunk[3];
0406: int length = itsCodeBufferTop - startPC;
0407:
0408: index = putInt16(startPC, codeAttribute, index);
0409: index = putInt16(length, codeAttribute, index);
0410: index = putInt16(nameIndex, codeAttribute, index);
0411: index = putInt16(descriptorIndex, codeAttribute, index);
0412: index = putInt16(register, codeAttribute, index);
0413: }
0414: }
0415:
0416: itsCurrentMethod.setCodeAttribute(codeAttribute);
0417:
0418: itsExceptionTable = null;
0419: itsExceptionTableTop = 0;
0420: itsLineNumberTableTop = 0;
0421: itsCodeBufferTop = 0;
0422: itsCurrentMethod = null;
0423: itsMaxStack = 0;
0424: itsStackTop = 0;
0425: itsLabelTableTop = 0;
0426: itsFixupTableTop = 0;
0427: itsVarDescriptors = null;
0428: }
0429:
0430: /**
0431: * Add the single-byte opcode to the current method.
0432: *
0433: * @param theOpCode the opcode of the bytecode
0434: */
0435: public void add(int theOpCode) {
0436: if (opcodeCount(theOpCode) != 0)
0437: throw new IllegalArgumentException("Unexpected operands");
0438: int newStack = itsStackTop + stackChange(theOpCode);
0439: if (newStack < 0 || Short.MAX_VALUE < newStack)
0440: badStack(newStack);
0441: if (DEBUGCODE)
0442: System.out.println("Add " + bytecodeStr(theOpCode));
0443: addToCodeBuffer(theOpCode);
0444: itsStackTop = (short) newStack;
0445: if (newStack > itsMaxStack)
0446: itsMaxStack = (short) newStack;
0447: if (DEBUGSTACK) {
0448: System.out.println("After " + bytecodeStr(theOpCode)
0449: + " stack = " + itsStackTop);
0450: }
0451: }
0452:
0453: /**
0454: * Add a single-operand opcode to the current method.
0455: *
0456: * @param theOpCode the opcode of the bytecode
0457: * @param theOperand the operand of the bytecode
0458: */
0459: public void add(int theOpCode, int theOperand) {
0460: if (DEBUGCODE) {
0461: System.out.println("Add " + bytecodeStr(theOpCode) + ", "
0462: + Integer.toHexString(theOperand));
0463: }
0464: int newStack = itsStackTop + stackChange(theOpCode);
0465: if (newStack < 0 || Short.MAX_VALUE < newStack)
0466: badStack(newStack);
0467:
0468: switch (theOpCode) {
0469: case ByteCode.GOTO:
0470: // fallthru...
0471: case ByteCode.IFEQ:
0472: case ByteCode.IFNE:
0473: case ByteCode.IFLT:
0474: case ByteCode.IFGE:
0475: case ByteCode.IFGT:
0476: case ByteCode.IFLE:
0477: case ByteCode.IF_ICMPEQ:
0478: case ByteCode.IF_ICMPNE:
0479: case ByteCode.IF_ICMPLT:
0480: case ByteCode.IF_ICMPGE:
0481: case ByteCode.IF_ICMPGT:
0482: case ByteCode.IF_ICMPLE:
0483: case ByteCode.IF_ACMPEQ:
0484: case ByteCode.IF_ACMPNE:
0485: case ByteCode.JSR:
0486: case ByteCode.IFNULL:
0487: case ByteCode.IFNONNULL: {
0488: if ((theOperand & 0x80000000) != 0x80000000) {
0489: if ((theOperand < 0) || (theOperand > 65535))
0490: throw new IllegalArgumentException(
0491: "Bad label for branch");
0492: }
0493: int branchPC = itsCodeBufferTop;
0494: addToCodeBuffer(theOpCode);
0495: if ((theOperand & 0x80000000) != 0x80000000) {
0496: // hard displacement
0497: addToCodeInt16(theOperand);
0498: } else { // a label
0499: int targetPC = getLabelPC(theOperand);
0500: if (DEBUGLABELS) {
0501: int theLabel = theOperand & 0x7FFFFFFF;
0502: System.out.println("Fixing branch to " + theLabel
0503: + " at " + targetPC + " from " + branchPC);
0504: }
0505: if (targetPC != -1) {
0506: int offset = targetPC - branchPC;
0507: addToCodeInt16(offset);
0508: } else {
0509: addLabelFixup(theOperand, branchPC + 1);
0510: addToCodeInt16(0);
0511: }
0512: }
0513: }
0514: break;
0515:
0516: case ByteCode.BIPUSH:
0517: if ((byte) theOperand != theOperand)
0518: throw new IllegalArgumentException("out of range byte");
0519: addToCodeBuffer(theOpCode);
0520: addToCodeBuffer((byte) theOperand);
0521: break;
0522:
0523: case ByteCode.SIPUSH:
0524: if ((short) theOperand != theOperand)
0525: throw new IllegalArgumentException("out of range short");
0526: addToCodeBuffer(theOpCode);
0527: addToCodeInt16(theOperand);
0528: break;
0529:
0530: case ByteCode.NEWARRAY:
0531: if (!(0 <= theOperand && theOperand < 256))
0532: throw new IllegalArgumentException("out of range index");
0533: addToCodeBuffer(theOpCode);
0534: addToCodeBuffer(theOperand);
0535: break;
0536:
0537: case ByteCode.GETFIELD:
0538: case ByteCode.PUTFIELD:
0539: if (!(0 <= theOperand && theOperand < 65536))
0540: throw new IllegalArgumentException("out of range field");
0541: addToCodeBuffer(theOpCode);
0542: addToCodeInt16(theOperand);
0543: break;
0544:
0545: case ByteCode.LDC:
0546: case ByteCode.LDC_W:
0547: case ByteCode.LDC2_W:
0548: if (!(0 <= theOperand && theOperand < 65536))
0549: throw new IllegalArgumentException("out of range index");
0550: if (theOperand >= 256 || theOpCode == ByteCode.LDC_W
0551: || theOpCode == ByteCode.LDC2_W) {
0552: if (theOpCode == ByteCode.LDC) {
0553: addToCodeBuffer(ByteCode.LDC_W);
0554: } else {
0555: addToCodeBuffer(theOpCode);
0556: }
0557: addToCodeInt16(theOperand);
0558: } else {
0559: addToCodeBuffer(theOpCode);
0560: addToCodeBuffer(theOperand);
0561: }
0562: break;
0563:
0564: case ByteCode.RET:
0565: case ByteCode.ILOAD:
0566: case ByteCode.LLOAD:
0567: case ByteCode.FLOAD:
0568: case ByteCode.DLOAD:
0569: case ByteCode.ALOAD:
0570: case ByteCode.ISTORE:
0571: case ByteCode.LSTORE:
0572: case ByteCode.FSTORE:
0573: case ByteCode.DSTORE:
0574: case ByteCode.ASTORE:
0575: if (!(0 <= theOperand && theOperand < 65536))
0576: throw new ClassFileFormatException(
0577: "out of range variable");
0578: if (theOperand >= 256) {
0579: addToCodeBuffer(ByteCode.WIDE);
0580: addToCodeBuffer(theOpCode);
0581: addToCodeInt16(theOperand);
0582: } else {
0583: addToCodeBuffer(theOpCode);
0584: addToCodeBuffer(theOperand);
0585: }
0586: break;
0587:
0588: default:
0589: throw new IllegalArgumentException(
0590: "Unexpected opcode for 1 operand");
0591: }
0592:
0593: itsStackTop = (short) newStack;
0594: if (newStack > itsMaxStack)
0595: itsMaxStack = (short) newStack;
0596: if (DEBUGSTACK) {
0597: System.out.println("After " + bytecodeStr(theOpCode)
0598: + " stack = " + itsStackTop);
0599: }
0600: }
0601:
0602: /**
0603: * Generate the load constant bytecode for the given integer.
0604: *
0605: * @param k the constant
0606: */
0607: public void addLoadConstant(int k) {
0608: switch (k) {
0609: case 0:
0610: add(ByteCode.ICONST_0);
0611: break;
0612: case 1:
0613: add(ByteCode.ICONST_1);
0614: break;
0615: case 2:
0616: add(ByteCode.ICONST_2);
0617: break;
0618: case 3:
0619: add(ByteCode.ICONST_3);
0620: break;
0621: case 4:
0622: add(ByteCode.ICONST_4);
0623: break;
0624: case 5:
0625: add(ByteCode.ICONST_5);
0626: break;
0627: default:
0628: add(ByteCode.LDC, itsConstantPool.addConstant(k));
0629: break;
0630: }
0631: }
0632:
0633: /**
0634: * Generate the load constant bytecode for the given long.
0635: *
0636: * @param k the constant
0637: */
0638: public void addLoadConstant(long k) {
0639: add(ByteCode.LDC2_W, itsConstantPool.addConstant(k));
0640: }
0641:
0642: /**
0643: * Generate the load constant bytecode for the given float.
0644: *
0645: * @param k the constant
0646: */
0647: public void addLoadConstant(float k) {
0648: add(ByteCode.LDC, itsConstantPool.addConstant(k));
0649: }
0650:
0651: /**
0652: * Generate the load constant bytecode for the given double.
0653: *
0654: * @param k the constant
0655: */
0656: public void addLoadConstant(double k) {
0657: add(ByteCode.LDC2_W, itsConstantPool.addConstant(k));
0658: }
0659:
0660: /**
0661: * Generate the load constant bytecode for the given string.
0662: *
0663: * @param k the constant
0664: */
0665: public void addLoadConstant(String k) {
0666: add(ByteCode.LDC, itsConstantPool.addConstant(k));
0667: }
0668:
0669: /**
0670: * Add the given two-operand bytecode to the current method.
0671: *
0672: * @param theOpCode the opcode of the bytecode
0673: * @param theOperand1 the first operand of the bytecode
0674: * @param theOperand2 the second operand of the bytecode
0675: */
0676: public void add(int theOpCode, int theOperand1, int theOperand2) {
0677: if (DEBUGCODE) {
0678: System.out.println("Add " + bytecodeStr(theOpCode) + ", "
0679: + Integer.toHexString(theOperand1) + ", "
0680: + Integer.toHexString(theOperand2));
0681: }
0682: int newStack = itsStackTop + stackChange(theOpCode);
0683: if (newStack < 0 || Short.MAX_VALUE < newStack)
0684: badStack(newStack);
0685:
0686: if (theOpCode == ByteCode.IINC) {
0687: if (!(0 <= theOperand1 && theOperand1 < 65536))
0688: throw new ClassFileFormatException(
0689: "out of range variable");
0690: if (!(0 <= theOperand2 && theOperand2 < 65536))
0691: throw new ClassFileFormatException(
0692: "out of range increment");
0693:
0694: if (theOperand1 > 255 || theOperand2 < -128
0695: || theOperand2 > 127) {
0696: addToCodeBuffer(ByteCode.WIDE);
0697: addToCodeBuffer(ByteCode.IINC);
0698: addToCodeInt16(theOperand1);
0699: addToCodeInt16(theOperand2);
0700: } else {
0701: addToCodeBuffer(ByteCode.WIDE);
0702: addToCodeBuffer(ByteCode.IINC);
0703: addToCodeBuffer(theOperand1);
0704: addToCodeBuffer(theOperand2);
0705: }
0706: } else if (theOpCode == ByteCode.MULTIANEWARRAY) {
0707: if (!(0 <= theOperand1 && theOperand1 < 65536))
0708: throw new IllegalArgumentException("out of range index");
0709: if (!(0 <= theOperand2 && theOperand2 < 256))
0710: throw new IllegalArgumentException(
0711: "out of range dimensions");
0712:
0713: addToCodeBuffer(ByteCode.MULTIANEWARRAY);
0714: addToCodeInt16(theOperand1);
0715: addToCodeBuffer(theOperand2);
0716: } else {
0717: throw new IllegalArgumentException(
0718: "Unexpected opcode for 2 operands");
0719: }
0720: itsStackTop = (short) newStack;
0721: if (newStack > itsMaxStack)
0722: itsMaxStack = (short) newStack;
0723: if (DEBUGSTACK) {
0724: System.out.println("After " + bytecodeStr(theOpCode)
0725: + " stack = " + itsStackTop);
0726: }
0727:
0728: }
0729:
0730: public void add(int theOpCode, String className) {
0731: if (DEBUGCODE) {
0732: System.out.println("Add " + bytecodeStr(theOpCode) + ", "
0733: + className);
0734: }
0735: int newStack = itsStackTop + stackChange(theOpCode);
0736: if (newStack < 0 || Short.MAX_VALUE < newStack)
0737: badStack(newStack);
0738: switch (theOpCode) {
0739: case ByteCode.NEW:
0740: case ByteCode.ANEWARRAY:
0741: case ByteCode.CHECKCAST:
0742: case ByteCode.INSTANCEOF: {
0743: short classIndex = itsConstantPool.addClass(className);
0744: addToCodeBuffer(theOpCode);
0745: addToCodeInt16(classIndex);
0746: }
0747: break;
0748:
0749: default:
0750: throw new IllegalArgumentException(
0751: "bad opcode for class reference");
0752: }
0753: itsStackTop = (short) newStack;
0754: if (newStack > itsMaxStack)
0755: itsMaxStack = (short) newStack;
0756: if (DEBUGSTACK) {
0757: System.out.println("After " + bytecodeStr(theOpCode)
0758: + " stack = " + itsStackTop);
0759: }
0760: }
0761:
0762: public void add(int theOpCode, String className, String fieldName,
0763: String fieldType) {
0764: if (DEBUGCODE) {
0765: System.out.println("Add " + bytecodeStr(theOpCode) + ", "
0766: + className + ", " + fieldName + ", " + fieldType);
0767: }
0768: int newStack = itsStackTop + stackChange(theOpCode);
0769: char fieldTypeChar = fieldType.charAt(0);
0770: int fieldSize = (fieldTypeChar == 'J' || fieldTypeChar == 'D') ? 2
0771: : 1;
0772: switch (theOpCode) {
0773: case ByteCode.GETFIELD:
0774: case ByteCode.GETSTATIC:
0775: newStack += fieldSize;
0776: break;
0777: case ByteCode.PUTSTATIC:
0778: case ByteCode.PUTFIELD:
0779: newStack -= fieldSize;
0780: break;
0781: default:
0782: throw new IllegalArgumentException(
0783: "bad opcode for field reference");
0784: }
0785: if (newStack < 0 || Short.MAX_VALUE < newStack)
0786: badStack(newStack);
0787: short fieldRefIndex = itsConstantPool.addFieldRef(className,
0788: fieldName, fieldType);
0789: addToCodeBuffer(theOpCode);
0790: addToCodeInt16(fieldRefIndex);
0791:
0792: itsStackTop = (short) newStack;
0793: if (newStack > itsMaxStack)
0794: itsMaxStack = (short) newStack;
0795: if (DEBUGSTACK) {
0796: System.out.println("After " + bytecodeStr(theOpCode)
0797: + " stack = " + itsStackTop);
0798: }
0799: }
0800:
0801: public void addInvoke(int theOpCode, String className,
0802: String methodName, String methodType) {
0803: if (DEBUGCODE) {
0804: System.out
0805: .println("Add " + bytecodeStr(theOpCode) + ", "
0806: + className + ", " + methodName + ", "
0807: + methodType);
0808: }
0809: int parameterInfo = sizeOfParameters(methodType);
0810: int parameterCount = parameterInfo >>> 16;
0811: int stackDiff = (short) parameterInfo;
0812:
0813: int newStack = itsStackTop + stackDiff;
0814: newStack += stackChange(theOpCode); // adjusts for 'this'
0815: if (newStack < 0 || Short.MAX_VALUE < newStack)
0816: badStack(newStack);
0817:
0818: switch (theOpCode) {
0819: case ByteCode.INVOKEVIRTUAL:
0820: case ByteCode.INVOKESPECIAL:
0821: case ByteCode.INVOKESTATIC:
0822: case ByteCode.INVOKEINTERFACE: {
0823: addToCodeBuffer(theOpCode);
0824: if (theOpCode == ByteCode.INVOKEINTERFACE) {
0825: short ifMethodRefIndex = itsConstantPool
0826: .addInterfaceMethodRef(className, methodName,
0827: methodType);
0828: addToCodeInt16(ifMethodRefIndex);
0829: addToCodeBuffer(parameterCount + 1);
0830: addToCodeBuffer(0);
0831: } else {
0832: short methodRefIndex = itsConstantPool.addMethodRef(
0833: className, methodName, methodType);
0834: addToCodeInt16(methodRefIndex);
0835: }
0836: }
0837: break;
0838:
0839: default:
0840: throw new IllegalArgumentException(
0841: "bad opcode for method reference");
0842: }
0843: itsStackTop = (short) newStack;
0844: if (newStack > itsMaxStack)
0845: itsMaxStack = (short) newStack;
0846: if (DEBUGSTACK) {
0847: System.out.println("After " + bytecodeStr(theOpCode)
0848: + " stack = " + itsStackTop);
0849: }
0850: }
0851:
0852: /**
0853: * Generate code to load the given integer on stack.
0854: *
0855: * @param k the constant
0856: */
0857: public void addPush(int k) {
0858: if ((byte) k == k) {
0859: if (k == -1) {
0860: add(ByteCode.ICONST_M1);
0861: } else if (0 <= k && k <= 5) {
0862: add((byte) (ByteCode.ICONST_0 + k));
0863: } else {
0864: add(ByteCode.BIPUSH, (byte) k);
0865: }
0866: } else if ((short) k == k) {
0867: add(ByteCode.SIPUSH, (short) k);
0868: } else {
0869: addLoadConstant(k);
0870: }
0871: }
0872:
0873: public void addPush(boolean k) {
0874: add(k ? ByteCode.ICONST_1 : ByteCode.ICONST_0);
0875: }
0876:
0877: /**
0878: * Generate code to load the given long on stack.
0879: *
0880: * @param k the constant
0881: */
0882: public void addPush(long k) {
0883: int ik = (int) k;
0884: if (ik == k) {
0885: addPush(ik);
0886: add(ByteCode.I2L);
0887: } else {
0888: addLoadConstant(k);
0889: }
0890: }
0891:
0892: /**
0893: * Generate code to load the given double on stack.
0894: *
0895: * @param k the constant
0896: */
0897: public void addPush(double k) {
0898: if (k == 0.0) {
0899: // zero
0900: add(ByteCode.DCONST_0);
0901: if (1.0 / k < 0) {
0902: // Negative zero
0903: add(ByteCode.DNEG);
0904: }
0905: } else if (k == 1.0 || k == -1.0) {
0906: add(ByteCode.DCONST_1);
0907: if (k < 0) {
0908: add(ByteCode.DNEG);
0909: }
0910: } else {
0911: addLoadConstant(k);
0912: }
0913: }
0914:
0915: /**
0916: * Generate the code to leave on stack the given string even if the
0917: * string encoding exeeds the class file limit for single string constant
0918: *
0919: * @param k the constant
0920: */
0921: public void addPush(String k) {
0922: int length = k.length();
0923: int limit = itsConstantPool.getUtfEncodingLimit(k, 0, length);
0924: if (limit == length) {
0925: addLoadConstant(k);
0926: return;
0927: }
0928: // Split string into picies fitting the UTF limit and generate code for
0929: // StringBuffer sb = new StringBuffer(length);
0930: // sb.append(loadConstant(piece_1));
0931: // ...
0932: // sb.append(loadConstant(piece_N));
0933: // sb.toString();
0934: final String SB = "java/lang/StringBuffer";
0935: add(ByteCode.NEW, SB);
0936: add(ByteCode.DUP);
0937: addPush(length);
0938: addInvoke(ByteCode.INVOKESPECIAL, SB, "<init>", "(I)V");
0939: int cursor = 0;
0940: for (;;) {
0941: add(ByteCode.DUP);
0942: String s = k.substring(cursor, limit);
0943: addLoadConstant(s);
0944: addInvoke(ByteCode.INVOKEVIRTUAL, SB, "append",
0945: "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
0946: add(ByteCode.POP);
0947: if (limit == length) {
0948: break;
0949: }
0950: cursor = limit;
0951: limit = itsConstantPool.getUtfEncodingLimit(k, limit,
0952: length);
0953: }
0954: addInvoke(ByteCode.INVOKEVIRTUAL, SB, "toString",
0955: "()Ljava/lang/String;");
0956: }
0957:
0958: /**
0959: * Check if k fits limit on string constant size imposed by class file
0960: * format.
0961: *
0962: * @param k the string constant
0963: */
0964: public boolean isUnderStringSizeLimit(String k) {
0965: return itsConstantPool.isUnderUtfEncodingLimit(k);
0966: }
0967:
0968: /**
0969: * Store integer from stack top into the given local.
0970: *
0971: * @param local number of local register
0972: */
0973: public void addIStore(int local) {
0974: xop(ByteCode.ISTORE_0, ByteCode.ISTORE, local);
0975: }
0976:
0977: /**
0978: * Store long from stack top into the given local.
0979: *
0980: * @param local number of local register
0981: */
0982: public void addLStore(int local) {
0983: xop(ByteCode.LSTORE_0, ByteCode.LSTORE, local);
0984: }
0985:
0986: /**
0987: * Store float from stack top into the given local.
0988: *
0989: * @param local number of local register
0990: */
0991: public void addFStore(int local) {
0992: xop(ByteCode.FSTORE_0, ByteCode.FSTORE, local);
0993: }
0994:
0995: /**
0996: * Store double from stack top into the given local.
0997: *
0998: * @param local number of local register
0999: */
1000: public void addDStore(int local) {
1001: xop(ByteCode.DSTORE_0, ByteCode.DSTORE, local);
1002: }
1003:
1004: /**
1005: * Store object from stack top into the given local.
1006: *
1007: * @param local number of local register
1008: */
1009: public void addAStore(int local) {
1010: xop(ByteCode.ASTORE_0, ByteCode.ASTORE, local);
1011: }
1012:
1013: /**
1014: * Load integer from the given local into stack.
1015: *
1016: * @param local number of local register
1017: */
1018: public void addILoad(int local) {
1019: xop(ByteCode.ILOAD_0, ByteCode.ILOAD, local);
1020: }
1021:
1022: /**
1023: * Load long from the given local into stack.
1024: *
1025: * @param local number of local register
1026: */
1027: public void addLLoad(int local) {
1028: xop(ByteCode.LLOAD_0, ByteCode.LLOAD, local);
1029: }
1030:
1031: /**
1032: * Load float from the given local into stack.
1033: *
1034: * @param local number of local register
1035: */
1036: public void addFLoad(int local) {
1037: xop(ByteCode.FLOAD_0, ByteCode.FLOAD, local);
1038: }
1039:
1040: /**
1041: * Load double from the given local into stack.
1042: *
1043: * @param local number of local register
1044: */
1045: public void addDLoad(int local) {
1046: xop(ByteCode.DLOAD_0, ByteCode.DLOAD, local);
1047: }
1048:
1049: /**
1050: * Load object from the given local into stack.
1051: *
1052: * @param local number of local register
1053: */
1054: public void addALoad(int local) {
1055: xop(ByteCode.ALOAD_0, ByteCode.ALOAD, local);
1056: }
1057:
1058: /**
1059: * Load "this" into stack.
1060: */
1061: public void addLoadThis() {
1062: add(ByteCode.ALOAD_0);
1063: }
1064:
1065: private void xop(int shortOp, int op, int local) {
1066: switch (local) {
1067: case 0:
1068: add(shortOp);
1069: break;
1070: case 1:
1071: add(shortOp + 1);
1072: break;
1073: case 2:
1074: add(shortOp + 2);
1075: break;
1076: case 3:
1077: add(shortOp + 3);
1078: break;
1079: default:
1080: add(op, local);
1081: }
1082: }
1083:
1084: public int addTableSwitch(int low, int high) {
1085: if (DEBUGCODE) {
1086: System.out.println("Add "
1087: + bytecodeStr(ByteCode.TABLESWITCH) + " " + low
1088: + " " + high);
1089: }
1090: if (low > high)
1091: throw new ClassFileFormatException("Bad bounds: " + low
1092: + ' ' + high);
1093:
1094: int newStack = itsStackTop + stackChange(ByteCode.TABLESWITCH);
1095: if (newStack < 0 || Short.MAX_VALUE < newStack)
1096: badStack(newStack);
1097:
1098: int entryCount = high - low + 1;
1099: int padSize = 3 & ~itsCodeBufferTop; // == 3 - itsCodeBufferTop % 4
1100:
1101: int N = addReservedCodeSpace(1 + padSize + 4
1102: * (1 + 2 + entryCount));
1103: int switchStart = N;
1104: itsCodeBuffer[N++] = (byte) ByteCode.TABLESWITCH;
1105: while (padSize != 0) {
1106: itsCodeBuffer[N++] = 0;
1107: --padSize;
1108: }
1109: N += 4; // skip default offset
1110: N = putInt32(low, itsCodeBuffer, N);
1111: putInt32(high, itsCodeBuffer, N);
1112:
1113: itsStackTop = (short) newStack;
1114: if (newStack > itsMaxStack)
1115: itsMaxStack = (short) newStack;
1116: if (DEBUGSTACK) {
1117: System.out.println("After "
1118: + bytecodeStr(ByteCode.TABLESWITCH) + " stack = "
1119: + itsStackTop);
1120: }
1121:
1122: return switchStart;
1123: }
1124:
1125: public final void markTableSwitchDefault(int switchStart) {
1126: setTableSwitchJump(switchStart, -1, itsCodeBufferTop);
1127: }
1128:
1129: public final void markTableSwitchCase(int switchStart, int caseIndex) {
1130: setTableSwitchJump(switchStart, caseIndex, itsCodeBufferTop);
1131: }
1132:
1133: public final void markTableSwitchCase(int switchStart,
1134: int caseIndex, int stackTop) {
1135: if (!(0 <= stackTop && stackTop <= itsMaxStack))
1136: throw new IllegalArgumentException("Bad stack index: "
1137: + stackTop);
1138: itsStackTop = (short) stackTop;
1139: setTableSwitchJump(switchStart, caseIndex, itsCodeBufferTop);
1140: }
1141:
1142: public void setTableSwitchJump(int switchStart, int caseIndex,
1143: int jumpTarget) {
1144: if (!(0 <= jumpTarget && jumpTarget <= itsCodeBufferTop))
1145: throw new IllegalArgumentException("Bad jump target: "
1146: + jumpTarget);
1147: if (!(caseIndex >= -1))
1148: throw new IllegalArgumentException("Bad case index: "
1149: + caseIndex);
1150:
1151: int padSize = 3 & ~switchStart; // == 3 - switchStart % 4
1152: int caseOffset;
1153: if (caseIndex < 0) {
1154: // default label
1155: caseOffset = switchStart + 1 + padSize;
1156: } else {
1157: caseOffset = switchStart + 1 + padSize + 4
1158: * (3 + caseIndex);
1159: }
1160: if (!(0 <= switchStart && switchStart <= itsCodeBufferTop - 4
1161: * 4 - padSize - 1)) {
1162: throw new IllegalArgumentException(switchStart
1163: + " is outside a possible range of tableswitch"
1164: + " in already generated code");
1165: }
1166: if ((0xFF & itsCodeBuffer[switchStart]) != ByteCode.TABLESWITCH) {
1167: throw new IllegalArgumentException(switchStart
1168: + " is not offset of tableswitch statement");
1169: }
1170: if (!(0 <= caseOffset && caseOffset + 4 <= itsCodeBufferTop)) {
1171: // caseIndex >= -1 does not guarantee that caseOffset >= 0 due
1172: // to a possible overflow.
1173: throw new ClassFileFormatException("Too big case index: "
1174: + caseIndex);
1175: }
1176: // ALERT: perhaps check against case bounds?
1177: putInt32(jumpTarget - switchStart, itsCodeBuffer, caseOffset);
1178: }
1179:
1180: public int acquireLabel() {
1181: int top = itsLabelTableTop;
1182: if (itsLabelTable == null || top == itsLabelTable.length) {
1183: if (itsLabelTable == null) {
1184: itsLabelTable = new int[MIN_LABEL_TABLE_SIZE];
1185: } else {
1186: int[] tmp = new int[itsLabelTable.length * 2];
1187: System.arraycopy(itsLabelTable, 0, tmp, 0, top);
1188: itsLabelTable = tmp;
1189: }
1190: }
1191: itsLabelTableTop = top + 1;
1192: itsLabelTable[top] = -1;
1193: return top | 0x80000000;
1194: }
1195:
1196: public void markLabel(int label) {
1197: if (!(label < 0))
1198: throw new IllegalArgumentException("Bad label, no biscuit");
1199:
1200: label &= 0x7FFFFFFF;
1201: if (label > itsLabelTableTop)
1202: throw new IllegalArgumentException("Bad label");
1203:
1204: if (itsLabelTable[label] != -1) {
1205: throw new IllegalStateException("Can only mark label once");
1206: }
1207:
1208: itsLabelTable[label] = itsCodeBufferTop;
1209: }
1210:
1211: public void markLabel(int label, short stackTop) {
1212: markLabel(label);
1213: itsStackTop = stackTop;
1214: }
1215:
1216: public void markHandler(int theLabel) {
1217: itsStackTop = 1;
1218: markLabel(theLabel);
1219: }
1220:
1221: private int getLabelPC(int label) {
1222: if (!(label < 0))
1223: throw new IllegalArgumentException("Bad label, no biscuit");
1224: label &= 0x7FFFFFFF;
1225: if (!(label < itsLabelTableTop))
1226: throw new IllegalArgumentException("Bad label");
1227: return itsLabelTable[label];
1228: }
1229:
1230: private void addLabelFixup(int label, int fixupSite) {
1231: if (!(label < 0))
1232: throw new IllegalArgumentException("Bad label, no biscuit");
1233: label &= 0x7FFFFFFF;
1234: if (!(label < itsLabelTableTop))
1235: throw new IllegalArgumentException("Bad label");
1236: int top = itsFixupTableTop;
1237: if (itsFixupTable == null || top == itsFixupTable.length) {
1238: if (itsFixupTable == null) {
1239: itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE];
1240: } else {
1241: long[] tmp = new long[itsFixupTable.length * 2];
1242: System.arraycopy(itsFixupTable, 0, tmp, 0, top);
1243: itsFixupTable = tmp;
1244: }
1245: }
1246: itsFixupTableTop = top + 1;
1247: itsFixupTable[top] = ((long) label << 32) | fixupSite;
1248: }
1249:
1250: private void fixLabelGotos() {
1251: byte[] codeBuffer = itsCodeBuffer;
1252: for (int i = 0; i < itsFixupTableTop; i++) {
1253: long fixup = itsFixupTable[i];
1254: int label = (int) (fixup >> 32);
1255: int fixupSite = (int) fixup;
1256: int pc = itsLabelTable[label];
1257: if (pc == -1) {
1258: // Unlocated label
1259: throw new RuntimeException();
1260: }
1261: // -1 to get delta from instruction start
1262: int offset = pc - (fixupSite - 1);
1263: if ((short) offset != offset) {
1264: throw new ClassFileFormatException(
1265: "Program too complex: too big jump offset");
1266: }
1267: codeBuffer[fixupSite] = (byte) (offset >> 8);
1268: codeBuffer[fixupSite + 1] = (byte) offset;
1269: }
1270: itsFixupTableTop = 0;
1271: }
1272:
1273: /**
1274: * Get the current offset into the code of the current method.
1275: *
1276: * @return an integer representing the offset
1277: */
1278: public int getCurrentCodeOffset() {
1279: return itsCodeBufferTop;
1280: }
1281:
1282: public short getStackTop() {
1283: return itsStackTop;
1284: }
1285:
1286: public void setStackTop(short n) {
1287: itsStackTop = n;
1288: }
1289:
1290: public void adjustStackTop(int delta) {
1291: int newStack = itsStackTop + delta;
1292: if (newStack < 0 || Short.MAX_VALUE < newStack)
1293: badStack(newStack);
1294: itsStackTop = (short) newStack;
1295: if (newStack > itsMaxStack)
1296: itsMaxStack = (short) newStack;
1297: if (DEBUGSTACK) {
1298: System.out.println("After " + "adjustStackTop(" + delta
1299: + ")" + " stack = " + itsStackTop);
1300: }
1301: }
1302:
1303: private void addToCodeBuffer(int b) {
1304: int N = addReservedCodeSpace(1);
1305: itsCodeBuffer[N] = (byte) b;
1306: }
1307:
1308: private void addToCodeInt16(int value) {
1309: int N = addReservedCodeSpace(2);
1310: putInt16(value, itsCodeBuffer, N);
1311: }
1312:
1313: private int addReservedCodeSpace(int size) {
1314: if (itsCurrentMethod == null)
1315: throw new IllegalArgumentException("No method to add to");
1316: int oldTop = itsCodeBufferTop;
1317: int newTop = oldTop + size;
1318: if (newTop > itsCodeBuffer.length) {
1319: int newSize = itsCodeBuffer.length * 2;
1320: if (newTop > newSize) {
1321: newSize = newTop;
1322: }
1323: byte[] tmp = new byte[newSize];
1324: System.arraycopy(itsCodeBuffer, 0, tmp, 0, oldTop);
1325: itsCodeBuffer = tmp;
1326: }
1327: itsCodeBufferTop = newTop;
1328: return oldTop;
1329: }
1330:
1331: public void addExceptionHandler(int startLabel, int endLabel,
1332: int handlerLabel, String catchClassName) {
1333: if ((startLabel & 0x80000000) != 0x80000000)
1334: throw new IllegalArgumentException("Bad startLabel");
1335: if ((endLabel & 0x80000000) != 0x80000000)
1336: throw new IllegalArgumentException("Bad endLabel");
1337: if ((handlerLabel & 0x80000000) != 0x80000000)
1338: throw new IllegalArgumentException("Bad handlerLabel");
1339:
1340: /*
1341: * If catchClassName is null, use 0 for the catch_type_index; which
1342: * means catch everything. (Even when the verifier has let you throw
1343: * something other than a Throwable.)
1344: */
1345: short catch_type_index = (catchClassName == null) ? 0
1346: : itsConstantPool.addClass(catchClassName);
1347: ExceptionTableEntry newEntry = new ExceptionTableEntry(
1348: startLabel, endLabel, handlerLabel, catch_type_index);
1349: int N = itsExceptionTableTop;
1350: if (N == 0) {
1351: itsExceptionTable = new ExceptionTableEntry[ExceptionTableSize];
1352: } else if (N == itsExceptionTable.length) {
1353: ExceptionTableEntry[] tmp = new ExceptionTableEntry[N * 2];
1354: System.arraycopy(itsExceptionTable, 0, tmp, 0, N);
1355: itsExceptionTable = tmp;
1356: }
1357: itsExceptionTable[N] = newEntry;
1358: itsExceptionTableTop = N + 1;
1359:
1360: }
1361:
1362: public void addLineNumberEntry(short lineNumber) {
1363: if (itsCurrentMethod == null)
1364: throw new IllegalArgumentException("No method to stop");
1365: int N = itsLineNumberTableTop;
1366: if (N == 0) {
1367: itsLineNumberTable = new int[LineNumberTableSize];
1368: } else if (N == itsLineNumberTable.length) {
1369: int[] tmp = new int[N * 2];
1370: System.arraycopy(itsLineNumberTable, 0, tmp, 0, N);
1371: itsLineNumberTable = tmp;
1372: }
1373: itsLineNumberTable[N] = (itsCodeBufferTop << 16) + lineNumber;
1374: itsLineNumberTableTop = N + 1;
1375: }
1376:
1377: /**
1378: * Write the class file to the OutputStream.
1379: *
1380: * @param oStream the stream to write to
1381: * @throws IOException if writing to the stream produces an exception
1382: */
1383: public void write(OutputStream oStream) throws IOException {
1384: byte[] array = toByteArray();
1385: oStream.write(array);
1386: }
1387:
1388: private int getWriteSize() {
1389: int size = 0;
1390:
1391: if (itsSourceFileNameIndex != 0) {
1392: itsConstantPool.addUtf8("SourceFile");
1393: }
1394:
1395: size += 8; //writeLong(FileHeaderConstant);
1396: size += itsConstantPool.getWriteSize();
1397: size += 2; //writeShort(itsFlags);
1398: size += 2; //writeShort(itsThisClassIndex);
1399: size += 2; //writeShort(itsSuperClassIndex);
1400: size += 2; //writeShort(itsInterfaces.size());
1401: size += 2 * itsInterfaces.size();
1402:
1403: size += 2; //writeShort(itsFields.size());
1404: for (int i = 0; i < itsFields.size(); i++) {
1405: size += ((ClassFileField) (itsFields.get(i)))
1406: .getWriteSize();
1407: }
1408:
1409: size += 2; //writeShort(itsMethods.size());
1410: for (int i = 0; i < itsMethods.size(); i++) {
1411: size += ((ClassFileMethod) (itsMethods.get(i)))
1412: .getWriteSize();
1413: }
1414:
1415: if (itsSourceFileNameIndex != 0) {
1416: size += 2; //writeShort(1); attributes count
1417: size += 2; //writeShort(sourceFileAttributeNameIndex);
1418: size += 4; //writeInt(2);
1419: size += 2; //writeShort(itsSourceFileNameIndex);
1420: } else {
1421: size += 2; //out.writeShort(0); no attributes
1422: }
1423:
1424: return size;
1425: }
1426:
1427: /**
1428: * Get the class file as array of bytesto the OutputStream.
1429: */
1430: public byte[] toByteArray() {
1431: int dataSize = getWriteSize();
1432: byte[] data = new byte[dataSize];
1433: int offset = 0;
1434:
1435: short sourceFileAttributeNameIndex = 0;
1436: if (itsSourceFileNameIndex != 0) {
1437: sourceFileAttributeNameIndex = itsConstantPool
1438: .addUtf8("SourceFile");
1439: }
1440:
1441: offset = putInt64(FileHeaderConstant, data, offset);
1442: offset = itsConstantPool.write(data, offset);
1443: offset = putInt16(itsFlags, data, offset);
1444: offset = putInt16(itsThisClassIndex, data, offset);
1445: offset = putInt16(itsSuperClassIndex, data, offset);
1446: offset = putInt16(itsInterfaces.size(), data, offset);
1447: for (int i = 0; i < itsInterfaces.size(); i++) {
1448: int interfaceIndex = ((Short) (itsInterfaces.get(i)))
1449: .shortValue();
1450: offset = putInt16(interfaceIndex, data, offset);
1451: }
1452: offset = putInt16(itsFields.size(), data, offset);
1453: for (int i = 0; i < itsFields.size(); i++) {
1454: ClassFileField field = (ClassFileField) itsFields.get(i);
1455: offset = field.write(data, offset);
1456: }
1457: offset = putInt16(itsMethods.size(), data, offset);
1458: for (int i = 0; i < itsMethods.size(); i++) {
1459: ClassFileMethod method = (ClassFileMethod) itsMethods
1460: .get(i);
1461: offset = method.write(data, offset);
1462: }
1463: if (itsSourceFileNameIndex != 0) {
1464: offset = putInt16(1, data, offset); // attributes count
1465: offset = putInt16(sourceFileAttributeNameIndex, data,
1466: offset);
1467: offset = putInt32(2, data, offset);
1468: offset = putInt16(itsSourceFileNameIndex, data, offset);
1469: } else {
1470: offset = putInt16(0, data, offset); // no attributes
1471: }
1472:
1473: if (offset != dataSize) {
1474: // Check getWriteSize is consistent with write!
1475: throw new RuntimeException();
1476: }
1477:
1478: return data;
1479: }
1480:
1481: static int putInt64(long value, byte[] array, int offset) {
1482: offset = putInt32((int) (value >>> 32), array, offset);
1483: return putInt32((int) value, array, offset);
1484: }
1485:
1486: private static void badStack(int value) {
1487: String s;
1488: if (value < 0) {
1489: s = "Stack underflow: " + value;
1490: } else {
1491: s = "Too big stack: " + value;
1492: }
1493: throw new IllegalStateException(s);
1494: }
1495:
1496: /*
1497: Really weird. Returns an int with # parameters in hi 16 bits, and
1498: stack difference removal of parameters from stack and pushing the
1499: result (it does not take into account removal of this in case of
1500: non-static methods).
1501: If Java really supported references we wouldn't have to be this
1502: perverted.
1503: */
1504: private static int sizeOfParameters(String pString) {
1505: int length = pString.length();
1506: int rightParenthesis = pString.lastIndexOf(')');
1507: if (3 <= length /* minimal signature takes at least 3 chars: ()V */
1508: && pString.charAt(0) == '(' && 1 <= rightParenthesis
1509: && rightParenthesis + 1 < length) {
1510: boolean ok = true;
1511: int index = 1;
1512: int stackDiff = 0;
1513: int count = 0;
1514: stringLoop: while (index != rightParenthesis) {
1515: switch (pString.charAt(index)) {
1516: default:
1517: ok = false;
1518: break stringLoop;
1519: case 'J':
1520: case 'D':
1521: --stackDiff;
1522: // fall thru
1523: case 'B':
1524: case 'S':
1525: case 'C':
1526: case 'I':
1527: case 'Z':
1528: case 'F':
1529: --stackDiff;
1530: ++count;
1531: ++index;
1532: continue;
1533: case '[':
1534: ++index;
1535: int c = pString.charAt(index);
1536: while (c == '[') {
1537: ++index;
1538: c = pString.charAt(index);
1539: }
1540: switch (c) {
1541: default:
1542: ok = false;
1543: break stringLoop;
1544: case 'J':
1545: case 'D':
1546: case 'B':
1547: case 'S':
1548: case 'C':
1549: case 'I':
1550: case 'Z':
1551: case 'F':
1552: --stackDiff;
1553: ++count;
1554: ++index;
1555: continue;
1556: case 'L':
1557: // fall thru
1558: }
1559: // fall thru
1560: case 'L': {
1561: --stackDiff;
1562: ++count;
1563: ++index;
1564: int semicolon = pString.indexOf(';', index);
1565: if (!(index + 1 <= semicolon && semicolon < rightParenthesis)) {
1566: ok = false;
1567: break stringLoop;
1568: }
1569: index = semicolon + 1;
1570: continue;
1571: }
1572: }
1573: }
1574: if (ok) {
1575: switch (pString.charAt(rightParenthesis + 1)) {
1576: default:
1577: ok = false;
1578: break;
1579: case 'J':
1580: case 'D':
1581: ++stackDiff;
1582: // fall thru
1583: case 'B':
1584: case 'S':
1585: case 'C':
1586: case 'I':
1587: case 'Z':
1588: case 'F':
1589: case 'L':
1590: case '[':
1591: ++stackDiff;
1592: // fall thru
1593: case 'V':
1594: break;
1595: }
1596: if (ok) {
1597: return ((count << 16) | (0xFFFF & stackDiff));
1598: }
1599: }
1600: }
1601: throw new IllegalArgumentException("Bad parameter signature: "
1602: + pString);
1603: }
1604:
1605: static int putInt16(int value, byte[] array, int offset) {
1606: array[offset + 0] = (byte) (value >>> 8);
1607: array[offset + 1] = (byte) value;
1608: return offset + 2;
1609: }
1610:
1611: static int putInt32(int value, byte[] array, int offset) {
1612: array[offset + 0] = (byte) (value >>> 24);
1613: array[offset + 1] = (byte) (value >>> 16);
1614: array[offset + 2] = (byte) (value >>> 8);
1615: array[offset + 3] = (byte) value;
1616: return offset + 4;
1617: }
1618:
1619: /**
1620: * Number of operands accompanying the opcode.
1621: */
1622: static int opcodeCount(int opcode) {
1623: switch (opcode) {
1624: case ByteCode.AALOAD:
1625: case ByteCode.AASTORE:
1626: case ByteCode.ACONST_NULL:
1627: case ByteCode.ALOAD_0:
1628: case ByteCode.ALOAD_1:
1629: case ByteCode.ALOAD_2:
1630: case ByteCode.ALOAD_3:
1631: case ByteCode.ARETURN:
1632: case ByteCode.ARRAYLENGTH:
1633: case ByteCode.ASTORE_0:
1634: case ByteCode.ASTORE_1:
1635: case ByteCode.ASTORE_2:
1636: case ByteCode.ASTORE_3:
1637: case ByteCode.ATHROW:
1638: case ByteCode.BALOAD:
1639: case ByteCode.BASTORE:
1640: case ByteCode.BREAKPOINT:
1641: case ByteCode.CALOAD:
1642: case ByteCode.CASTORE:
1643: case ByteCode.D2F:
1644: case ByteCode.D2I:
1645: case ByteCode.D2L:
1646: case ByteCode.DADD:
1647: case ByteCode.DALOAD:
1648: case ByteCode.DASTORE:
1649: case ByteCode.DCMPG:
1650: case ByteCode.DCMPL:
1651: case ByteCode.DCONST_0:
1652: case ByteCode.DCONST_1:
1653: case ByteCode.DDIV:
1654: case ByteCode.DLOAD_0:
1655: case ByteCode.DLOAD_1:
1656: case ByteCode.DLOAD_2:
1657: case ByteCode.DLOAD_3:
1658: case ByteCode.DMUL:
1659: case ByteCode.DNEG:
1660: case ByteCode.DREM:
1661: case ByteCode.DRETURN:
1662: case ByteCode.DSTORE_0:
1663: case ByteCode.DSTORE_1:
1664: case ByteCode.DSTORE_2:
1665: case ByteCode.DSTORE_3:
1666: case ByteCode.DSUB:
1667: case ByteCode.DUP:
1668: case ByteCode.DUP2:
1669: case ByteCode.DUP2_X1:
1670: case ByteCode.DUP2_X2:
1671: case ByteCode.DUP_X1:
1672: case ByteCode.DUP_X2:
1673: case ByteCode.F2D:
1674: case ByteCode.F2I:
1675: case ByteCode.F2L:
1676: case ByteCode.FADD:
1677: case ByteCode.FALOAD:
1678: case ByteCode.FASTORE:
1679: case ByteCode.FCMPG:
1680: case ByteCode.FCMPL:
1681: case ByteCode.FCONST_0:
1682: case ByteCode.FCONST_1:
1683: case ByteCode.FCONST_2:
1684: case ByteCode.FDIV:
1685: case ByteCode.FLOAD_0:
1686: case ByteCode.FLOAD_1:
1687: case ByteCode.FLOAD_2:
1688: case ByteCode.FLOAD_3:
1689: case ByteCode.FMUL:
1690: case ByteCode.FNEG:
1691: case ByteCode.FREM:
1692: case ByteCode.FRETURN:
1693: case ByteCode.FSTORE_0:
1694: case ByteCode.FSTORE_1:
1695: case ByteCode.FSTORE_2:
1696: case ByteCode.FSTORE_3:
1697: case ByteCode.FSUB:
1698: case ByteCode.I2B:
1699: case ByteCode.I2C:
1700: case ByteCode.I2D:
1701: case ByteCode.I2F:
1702: case ByteCode.I2L:
1703: case ByteCode.I2S:
1704: case ByteCode.IADD:
1705: case ByteCode.IALOAD:
1706: case ByteCode.IAND:
1707: case ByteCode.IASTORE:
1708: case ByteCode.ICONST_0:
1709: case ByteCode.ICONST_1:
1710: case ByteCode.ICONST_2:
1711: case ByteCode.ICONST_3:
1712: case ByteCode.ICONST_4:
1713: case ByteCode.ICONST_5:
1714: case ByteCode.ICONST_M1:
1715: case ByteCode.IDIV:
1716: case ByteCode.ILOAD_0:
1717: case ByteCode.ILOAD_1:
1718: case ByteCode.ILOAD_2:
1719: case ByteCode.ILOAD_3:
1720: case ByteCode.IMPDEP1:
1721: case ByteCode.IMPDEP2:
1722: case ByteCode.IMUL:
1723: case ByteCode.INEG:
1724: case ByteCode.IOR:
1725: case ByteCode.IREM:
1726: case ByteCode.IRETURN:
1727: case ByteCode.ISHL:
1728: case ByteCode.ISHR:
1729: case ByteCode.ISTORE_0:
1730: case ByteCode.ISTORE_1:
1731: case ByteCode.ISTORE_2:
1732: case ByteCode.ISTORE_3:
1733: case ByteCode.ISUB:
1734: case ByteCode.IUSHR:
1735: case ByteCode.IXOR:
1736: case ByteCode.L2D:
1737: case ByteCode.L2F:
1738: case ByteCode.L2I:
1739: case ByteCode.LADD:
1740: case ByteCode.LALOAD:
1741: case ByteCode.LAND:
1742: case ByteCode.LASTORE:
1743: case ByteCode.LCMP:
1744: case ByteCode.LCONST_0:
1745: case ByteCode.LCONST_1:
1746: case ByteCode.LDIV:
1747: case ByteCode.LLOAD_0:
1748: case ByteCode.LLOAD_1:
1749: case ByteCode.LLOAD_2:
1750: case ByteCode.LLOAD_3:
1751: case ByteCode.LMUL:
1752: case ByteCode.LNEG:
1753: case ByteCode.LOR:
1754: case ByteCode.LREM:
1755: case ByteCode.LRETURN:
1756: case ByteCode.LSHL:
1757: case ByteCode.LSHR:
1758: case ByteCode.LSTORE_0:
1759: case ByteCode.LSTORE_1:
1760: case ByteCode.LSTORE_2:
1761: case ByteCode.LSTORE_3:
1762: case ByteCode.LSUB:
1763: case ByteCode.LUSHR:
1764: case ByteCode.LXOR:
1765: case ByteCode.MONITORENTER:
1766: case ByteCode.MONITOREXIT:
1767: case ByteCode.NOP:
1768: case ByteCode.POP:
1769: case ByteCode.POP2:
1770: case ByteCode.RETURN:
1771: case ByteCode.SALOAD:
1772: case ByteCode.SASTORE:
1773: case ByteCode.SWAP:
1774: case ByteCode.WIDE:
1775: return 0;
1776: case ByteCode.ALOAD:
1777: case ByteCode.ANEWARRAY:
1778: case ByteCode.ASTORE:
1779: case ByteCode.BIPUSH:
1780: case ByteCode.CHECKCAST:
1781: case ByteCode.DLOAD:
1782: case ByteCode.DSTORE:
1783: case ByteCode.FLOAD:
1784: case ByteCode.FSTORE:
1785: case ByteCode.GETFIELD:
1786: case ByteCode.GETSTATIC:
1787: case ByteCode.GOTO:
1788: case ByteCode.GOTO_W:
1789: case ByteCode.IFEQ:
1790: case ByteCode.IFGE:
1791: case ByteCode.IFGT:
1792: case ByteCode.IFLE:
1793: case ByteCode.IFLT:
1794: case ByteCode.IFNE:
1795: case ByteCode.IFNONNULL:
1796: case ByteCode.IFNULL:
1797: case ByteCode.IF_ACMPEQ:
1798: case ByteCode.IF_ACMPNE:
1799: case ByteCode.IF_ICMPEQ:
1800: case ByteCode.IF_ICMPGE:
1801: case ByteCode.IF_ICMPGT:
1802: case ByteCode.IF_ICMPLE:
1803: case ByteCode.IF_ICMPLT:
1804: case ByteCode.IF_ICMPNE:
1805: case ByteCode.ILOAD:
1806: case ByteCode.INSTANCEOF:
1807: case ByteCode.INVOKEINTERFACE:
1808: case ByteCode.INVOKESPECIAL:
1809: case ByteCode.INVOKESTATIC:
1810: case ByteCode.INVOKEVIRTUAL:
1811: case ByteCode.ISTORE:
1812: case ByteCode.JSR:
1813: case ByteCode.JSR_W:
1814: case ByteCode.LDC:
1815: case ByteCode.LDC2_W:
1816: case ByteCode.LDC_W:
1817: case ByteCode.LLOAD:
1818: case ByteCode.LSTORE:
1819: case ByteCode.NEW:
1820: case ByteCode.NEWARRAY:
1821: case ByteCode.PUTFIELD:
1822: case ByteCode.PUTSTATIC:
1823: case ByteCode.RET:
1824: case ByteCode.SIPUSH:
1825: return 1;
1826:
1827: case ByteCode.IINC:
1828: case ByteCode.MULTIANEWARRAY:
1829: return 2;
1830:
1831: case ByteCode.LOOKUPSWITCH:
1832: case ByteCode.TABLESWITCH:
1833: return -1;
1834: }
1835: throw new IllegalArgumentException("Bad opcode: " + opcode);
1836: }
1837:
1838: /**
1839: * The effect on the operand stack of a given opcode.
1840: */
1841: static int stackChange(int opcode) {
1842: // For INVOKE... accounts only for popping this (unless static),
1843: // ignoring parameters and return type
1844: switch (opcode) {
1845: case ByteCode.DASTORE:
1846: case ByteCode.LASTORE:
1847: return -4;
1848:
1849: case ByteCode.AASTORE:
1850: case ByteCode.BASTORE:
1851: case ByteCode.CASTORE:
1852: case ByteCode.DCMPG:
1853: case ByteCode.DCMPL:
1854: case ByteCode.FASTORE:
1855: case ByteCode.IASTORE:
1856: case ByteCode.LCMP:
1857: case ByteCode.SASTORE:
1858: return -3;
1859:
1860: case ByteCode.DADD:
1861: case ByteCode.DDIV:
1862: case ByteCode.DMUL:
1863: case ByteCode.DREM:
1864: case ByteCode.DRETURN:
1865: case ByteCode.DSTORE:
1866: case ByteCode.DSTORE_0:
1867: case ByteCode.DSTORE_1:
1868: case ByteCode.DSTORE_2:
1869: case ByteCode.DSTORE_3:
1870: case ByteCode.DSUB:
1871: case ByteCode.IF_ACMPEQ:
1872: case ByteCode.IF_ACMPNE:
1873: case ByteCode.IF_ICMPEQ:
1874: case ByteCode.IF_ICMPGE:
1875: case ByteCode.IF_ICMPGT:
1876: case ByteCode.IF_ICMPLE:
1877: case ByteCode.IF_ICMPLT:
1878: case ByteCode.IF_ICMPNE:
1879: case ByteCode.LADD:
1880: case ByteCode.LAND:
1881: case ByteCode.LDIV:
1882: case ByteCode.LMUL:
1883: case ByteCode.LOR:
1884: case ByteCode.LREM:
1885: case ByteCode.LRETURN:
1886: case ByteCode.LSTORE:
1887: case ByteCode.LSTORE_0:
1888: case ByteCode.LSTORE_1:
1889: case ByteCode.LSTORE_2:
1890: case ByteCode.LSTORE_3:
1891: case ByteCode.LSUB:
1892: case ByteCode.LXOR:
1893: case ByteCode.POP2:
1894: return -2;
1895:
1896: case ByteCode.AALOAD:
1897: case ByteCode.ARETURN:
1898: case ByteCode.ASTORE:
1899: case ByteCode.ASTORE_0:
1900: case ByteCode.ASTORE_1:
1901: case ByteCode.ASTORE_2:
1902: case ByteCode.ASTORE_3:
1903: case ByteCode.ATHROW:
1904: case ByteCode.BALOAD:
1905: case ByteCode.CALOAD:
1906: case ByteCode.D2F:
1907: case ByteCode.D2I:
1908: case ByteCode.FADD:
1909: case ByteCode.FALOAD:
1910: case ByteCode.FCMPG:
1911: case ByteCode.FCMPL:
1912: case ByteCode.FDIV:
1913: case ByteCode.FMUL:
1914: case ByteCode.FREM:
1915: case ByteCode.FRETURN:
1916: case ByteCode.FSTORE:
1917: case ByteCode.FSTORE_0:
1918: case ByteCode.FSTORE_1:
1919: case ByteCode.FSTORE_2:
1920: case ByteCode.FSTORE_3:
1921: case ByteCode.FSUB:
1922: case ByteCode.GETFIELD:
1923: case ByteCode.IADD:
1924: case ByteCode.IALOAD:
1925: case ByteCode.IAND:
1926: case ByteCode.IDIV:
1927: case ByteCode.IFEQ:
1928: case ByteCode.IFGE:
1929: case ByteCode.IFGT:
1930: case ByteCode.IFLE:
1931: case ByteCode.IFLT:
1932: case ByteCode.IFNE:
1933: case ByteCode.IFNONNULL:
1934: case ByteCode.IFNULL:
1935: case ByteCode.IMUL:
1936: case ByteCode.INVOKEINTERFACE: //
1937: case ByteCode.INVOKESPECIAL: // but needs to account for
1938: case ByteCode.INVOKEVIRTUAL: // pops 'this' (unless static)
1939: case ByteCode.IOR:
1940: case ByteCode.IREM:
1941: case ByteCode.IRETURN:
1942: case ByteCode.ISHL:
1943: case ByteCode.ISHR:
1944: case ByteCode.ISTORE:
1945: case ByteCode.ISTORE_0:
1946: case ByteCode.ISTORE_1:
1947: case ByteCode.ISTORE_2:
1948: case ByteCode.ISTORE_3:
1949: case ByteCode.ISUB:
1950: case ByteCode.IUSHR:
1951: case ByteCode.IXOR:
1952: case ByteCode.L2F:
1953: case ByteCode.L2I:
1954: case ByteCode.LOOKUPSWITCH:
1955: case ByteCode.LSHL:
1956: case ByteCode.LSHR:
1957: case ByteCode.LUSHR:
1958: case ByteCode.MONITORENTER:
1959: case ByteCode.MONITOREXIT:
1960: case ByteCode.POP:
1961: case ByteCode.PUTFIELD:
1962: case ByteCode.SALOAD:
1963: case ByteCode.TABLESWITCH:
1964: return -1;
1965:
1966: case ByteCode.ANEWARRAY:
1967: case ByteCode.ARRAYLENGTH:
1968: case ByteCode.BREAKPOINT:
1969: case ByteCode.CHECKCAST:
1970: case ByteCode.D2L:
1971: case ByteCode.DALOAD:
1972: case ByteCode.DNEG:
1973: case ByteCode.F2I:
1974: case ByteCode.FNEG:
1975: case ByteCode.GETSTATIC:
1976: case ByteCode.GOTO:
1977: case ByteCode.GOTO_W:
1978: case ByteCode.I2B:
1979: case ByteCode.I2C:
1980: case ByteCode.I2F:
1981: case ByteCode.I2S:
1982: case ByteCode.IINC:
1983: case ByteCode.IMPDEP1:
1984: case ByteCode.IMPDEP2:
1985: case ByteCode.INEG:
1986: case ByteCode.INSTANCEOF:
1987: case ByteCode.INVOKESTATIC:
1988: case ByteCode.L2D:
1989: case ByteCode.LALOAD:
1990: case ByteCode.LNEG:
1991: case ByteCode.NEWARRAY:
1992: case ByteCode.NOP:
1993: case ByteCode.PUTSTATIC:
1994: case ByteCode.RET:
1995: case ByteCode.RETURN:
1996: case ByteCode.SWAP:
1997: case ByteCode.WIDE:
1998: return 0;
1999:
2000: case ByteCode.ACONST_NULL:
2001: case ByteCode.ALOAD:
2002: case ByteCode.ALOAD_0:
2003: case ByteCode.ALOAD_1:
2004: case ByteCode.ALOAD_2:
2005: case ByteCode.ALOAD_3:
2006: case ByteCode.BIPUSH:
2007: case ByteCode.DUP:
2008: case ByteCode.DUP_X1:
2009: case ByteCode.DUP_X2:
2010: case ByteCode.F2D:
2011: case ByteCode.F2L:
2012: case ByteCode.FCONST_0:
2013: case ByteCode.FCONST_1:
2014: case ByteCode.FCONST_2:
2015: case ByteCode.FLOAD:
2016: case ByteCode.FLOAD_0:
2017: case ByteCode.FLOAD_1:
2018: case ByteCode.FLOAD_2:
2019: case ByteCode.FLOAD_3:
2020: case ByteCode.I2D:
2021: case ByteCode.I2L:
2022: case ByteCode.ICONST_0:
2023: case ByteCode.ICONST_1:
2024: case ByteCode.ICONST_2:
2025: case ByteCode.ICONST_3:
2026: case ByteCode.ICONST_4:
2027: case ByteCode.ICONST_5:
2028: case ByteCode.ICONST_M1:
2029: case ByteCode.ILOAD:
2030: case ByteCode.ILOAD_0:
2031: case ByteCode.ILOAD_1:
2032: case ByteCode.ILOAD_2:
2033: case ByteCode.ILOAD_3:
2034: case ByteCode.JSR:
2035: case ByteCode.JSR_W:
2036: case ByteCode.LDC:
2037: case ByteCode.LDC_W:
2038: case ByteCode.MULTIANEWARRAY:
2039: case ByteCode.NEW:
2040: case ByteCode.SIPUSH:
2041: return 1;
2042:
2043: case ByteCode.DCONST_0:
2044: case ByteCode.DCONST_1:
2045: case ByteCode.DLOAD:
2046: case ByteCode.DLOAD_0:
2047: case ByteCode.DLOAD_1:
2048: case ByteCode.DLOAD_2:
2049: case ByteCode.DLOAD_3:
2050: case ByteCode.DUP2:
2051: case ByteCode.DUP2_X1:
2052: case ByteCode.DUP2_X2:
2053: case ByteCode.LCONST_0:
2054: case ByteCode.LCONST_1:
2055: case ByteCode.LDC2_W:
2056: case ByteCode.LLOAD:
2057: case ByteCode.LLOAD_0:
2058: case ByteCode.LLOAD_1:
2059: case ByteCode.LLOAD_2:
2060: case ByteCode.LLOAD_3:
2061: return 2;
2062: }
2063: throw new IllegalArgumentException("Bad opcode: " + opcode);
2064: }
2065:
2066: /*
2067: * Number of bytes of operands generated after the opcode.
2068: * Not in use currently.
2069: */
2070: /*
2071: int extra(int opcode)
2072: {
2073: switch (opcode) {
2074: case ByteCode.AALOAD:
2075: case ByteCode.AASTORE:
2076: case ByteCode.ACONST_NULL:
2077: case ByteCode.ALOAD_0:
2078: case ByteCode.ALOAD_1:
2079: case ByteCode.ALOAD_2:
2080: case ByteCode.ALOAD_3:
2081: case ByteCode.ARETURN:
2082: case ByteCode.ARRAYLENGTH:
2083: case ByteCode.ASTORE_0:
2084: case ByteCode.ASTORE_1:
2085: case ByteCode.ASTORE_2:
2086: case ByteCode.ASTORE_3:
2087: case ByteCode.ATHROW:
2088: case ByteCode.BALOAD:
2089: case ByteCode.BASTORE:
2090: case ByteCode.BREAKPOINT:
2091: case ByteCode.CALOAD:
2092: case ByteCode.CASTORE:
2093: case ByteCode.D2F:
2094: case ByteCode.D2I:
2095: case ByteCode.D2L:
2096: case ByteCode.DADD:
2097: case ByteCode.DALOAD:
2098: case ByteCode.DASTORE:
2099: case ByteCode.DCMPG:
2100: case ByteCode.DCMPL:
2101: case ByteCode.DCONST_0:
2102: case ByteCode.DCONST_1:
2103: case ByteCode.DDIV:
2104: case ByteCode.DLOAD_0:
2105: case ByteCode.DLOAD_1:
2106: case ByteCode.DLOAD_2:
2107: case ByteCode.DLOAD_3:
2108: case ByteCode.DMUL:
2109: case ByteCode.DNEG:
2110: case ByteCode.DREM:
2111: case ByteCode.DRETURN:
2112: case ByteCode.DSTORE_0:
2113: case ByteCode.DSTORE_1:
2114: case ByteCode.DSTORE_2:
2115: case ByteCode.DSTORE_3:
2116: case ByteCode.DSUB:
2117: case ByteCode.DUP2:
2118: case ByteCode.DUP2_X1:
2119: case ByteCode.DUP2_X2:
2120: case ByteCode.DUP:
2121: case ByteCode.DUP_X1:
2122: case ByteCode.DUP_X2:
2123: case ByteCode.F2D:
2124: case ByteCode.F2I:
2125: case ByteCode.F2L:
2126: case ByteCode.FADD:
2127: case ByteCode.FALOAD:
2128: case ByteCode.FASTORE:
2129: case ByteCode.FCMPG:
2130: case ByteCode.FCMPL:
2131: case ByteCode.FCONST_0:
2132: case ByteCode.FCONST_1:
2133: case ByteCode.FCONST_2:
2134: case ByteCode.FDIV:
2135: case ByteCode.FLOAD_0:
2136: case ByteCode.FLOAD_1:
2137: case ByteCode.FLOAD_2:
2138: case ByteCode.FLOAD_3:
2139: case ByteCode.FMUL:
2140: case ByteCode.FNEG:
2141: case ByteCode.FREM:
2142: case ByteCode.FRETURN:
2143: case ByteCode.FSTORE_0:
2144: case ByteCode.FSTORE_1:
2145: case ByteCode.FSTORE_2:
2146: case ByteCode.FSTORE_3:
2147: case ByteCode.FSUB:
2148: case ByteCode.I2B:
2149: case ByteCode.I2C:
2150: case ByteCode.I2D:
2151: case ByteCode.I2F:
2152: case ByteCode.I2L:
2153: case ByteCode.I2S:
2154: case ByteCode.IADD:
2155: case ByteCode.IALOAD:
2156: case ByteCode.IAND:
2157: case ByteCode.IASTORE:
2158: case ByteCode.ICONST_0:
2159: case ByteCode.ICONST_1:
2160: case ByteCode.ICONST_2:
2161: case ByteCode.ICONST_3:
2162: case ByteCode.ICONST_4:
2163: case ByteCode.ICONST_5:
2164: case ByteCode.ICONST_M1:
2165: case ByteCode.IDIV:
2166: case ByteCode.ILOAD_0:
2167: case ByteCode.ILOAD_1:
2168: case ByteCode.ILOAD_2:
2169: case ByteCode.ILOAD_3:
2170: case ByteCode.IMPDEP1:
2171: case ByteCode.IMPDEP2:
2172: case ByteCode.IMUL:
2173: case ByteCode.INEG:
2174: case ByteCode.IOR:
2175: case ByteCode.IREM:
2176: case ByteCode.IRETURN:
2177: case ByteCode.ISHL:
2178: case ByteCode.ISHR:
2179: case ByteCode.ISTORE_0:
2180: case ByteCode.ISTORE_1:
2181: case ByteCode.ISTORE_2:
2182: case ByteCode.ISTORE_3:
2183: case ByteCode.ISUB:
2184: case ByteCode.IUSHR:
2185: case ByteCode.IXOR:
2186: case ByteCode.L2D:
2187: case ByteCode.L2F:
2188: case ByteCode.L2I:
2189: case ByteCode.LADD:
2190: case ByteCode.LALOAD:
2191: case ByteCode.LAND:
2192: case ByteCode.LASTORE:
2193: case ByteCode.LCMP:
2194: case ByteCode.LCONST_0:
2195: case ByteCode.LCONST_1:
2196: case ByteCode.LDIV:
2197: case ByteCode.LLOAD_0:
2198: case ByteCode.LLOAD_1:
2199: case ByteCode.LLOAD_2:
2200: case ByteCode.LLOAD_3:
2201: case ByteCode.LMUL:
2202: case ByteCode.LNEG:
2203: case ByteCode.LOR:
2204: case ByteCode.LREM:
2205: case ByteCode.LRETURN:
2206: case ByteCode.LSHL:
2207: case ByteCode.LSHR:
2208: case ByteCode.LSTORE_0:
2209: case ByteCode.LSTORE_1:
2210: case ByteCode.LSTORE_2:
2211: case ByteCode.LSTORE_3:
2212: case ByteCode.LSUB:
2213: case ByteCode.LUSHR:
2214: case ByteCode.LXOR:
2215: case ByteCode.MONITORENTER:
2216: case ByteCode.MONITOREXIT:
2217: case ByteCode.NOP:
2218: case ByteCode.POP2:
2219: case ByteCode.POP:
2220: case ByteCode.RETURN:
2221: case ByteCode.SALOAD:
2222: case ByteCode.SASTORE:
2223: case ByteCode.SWAP:
2224: case ByteCode.WIDE:
2225: return 0;
2226:
2227: case ByteCode.ALOAD:
2228: case ByteCode.ASTORE:
2229: case ByteCode.BIPUSH:
2230: case ByteCode.DLOAD:
2231: case ByteCode.DSTORE:
2232: case ByteCode.FLOAD:
2233: case ByteCode.FSTORE:
2234: case ByteCode.ILOAD:
2235: case ByteCode.ISTORE:
2236: case ByteCode.LDC:
2237: case ByteCode.LLOAD:
2238: case ByteCode.LSTORE:
2239: case ByteCode.NEWARRAY:
2240: case ByteCode.RET:
2241: return 1;
2242:
2243: case ByteCode.ANEWARRAY:
2244: case ByteCode.CHECKCAST:
2245: case ByteCode.GETFIELD:
2246: case ByteCode.GETSTATIC:
2247: case ByteCode.GOTO:
2248: case ByteCode.IFEQ:
2249: case ByteCode.IFGE:
2250: case ByteCode.IFGT:
2251: case ByteCode.IFLE:
2252: case ByteCode.IFLT:
2253: case ByteCode.IFNE:
2254: case ByteCode.IFNONNULL:
2255: case ByteCode.IFNULL:
2256: case ByteCode.IF_ACMPEQ:
2257: case ByteCode.IF_ACMPNE:
2258: case ByteCode.IF_ICMPEQ:
2259: case ByteCode.IF_ICMPGE:
2260: case ByteCode.IF_ICMPGT:
2261: case ByteCode.IF_ICMPLE:
2262: case ByteCode.IF_ICMPLT:
2263: case ByteCode.IF_ICMPNE:
2264: case ByteCode.IINC:
2265: case ByteCode.INSTANCEOF:
2266: case ByteCode.INVOKEINTERFACE:
2267: case ByteCode.INVOKESPECIAL:
2268: case ByteCode.INVOKESTATIC:
2269: case ByteCode.INVOKEVIRTUAL:
2270: case ByteCode.JSR:
2271: case ByteCode.LDC2_W:
2272: case ByteCode.LDC_W:
2273: case ByteCode.NEW:
2274: case ByteCode.PUTFIELD:
2275: case ByteCode.PUTSTATIC:
2276: case ByteCode.SIPUSH:
2277: return 2;
2278:
2279: case ByteCode.MULTIANEWARRAY:
2280: return 3;
2281:
2282: case ByteCode.GOTO_W:
2283: case ByteCode.JSR_W:
2284: return 4;
2285:
2286: case ByteCode.LOOKUPSWITCH: // depends on alignment
2287: case ByteCode.TABLESWITCH: // depends on alignment
2288: return -1;
2289: }
2290: throw new IllegalArgumentException("Bad opcode: "+opcode);
2291: }
2292: */
2293: private static String bytecodeStr(int code) {
2294: if (DEBUGSTACK || DEBUGCODE) {
2295: switch (code) {
2296: case ByteCode.NOP:
2297: return "nop";
2298: case ByteCode.ACONST_NULL:
2299: return "aconst_null";
2300: case ByteCode.ICONST_M1:
2301: return "iconst_m1";
2302: case ByteCode.ICONST_0:
2303: return "iconst_0";
2304: case ByteCode.ICONST_1:
2305: return "iconst_1";
2306: case ByteCode.ICONST_2:
2307: return "iconst_2";
2308: case ByteCode.ICONST_3:
2309: return "iconst_3";
2310: case ByteCode.ICONST_4:
2311: return "iconst_4";
2312: case ByteCode.ICONST_5:
2313: return "iconst_5";
2314: case ByteCode.LCONST_0:
2315: return "lconst_0";
2316: case ByteCode.LCONST_1:
2317: return "lconst_1";
2318: case ByteCode.FCONST_0:
2319: return "fconst_0";
2320: case ByteCode.FCONST_1:
2321: return "fconst_1";
2322: case ByteCode.FCONST_2:
2323: return "fconst_2";
2324: case ByteCode.DCONST_0:
2325: return "dconst_0";
2326: case ByteCode.DCONST_1:
2327: return "dconst_1";
2328: case ByteCode.BIPUSH:
2329: return "bipush";
2330: case ByteCode.SIPUSH:
2331: return "sipush";
2332: case ByteCode.LDC:
2333: return "ldc";
2334: case ByteCode.LDC_W:
2335: return "ldc_w";
2336: case ByteCode.LDC2_W:
2337: return "ldc2_w";
2338: case ByteCode.ILOAD:
2339: return "iload";
2340: case ByteCode.LLOAD:
2341: return "lload";
2342: case ByteCode.FLOAD:
2343: return "fload";
2344: case ByteCode.DLOAD:
2345: return "dload";
2346: case ByteCode.ALOAD:
2347: return "aload";
2348: case ByteCode.ILOAD_0:
2349: return "iload_0";
2350: case ByteCode.ILOAD_1:
2351: return "iload_1";
2352: case ByteCode.ILOAD_2:
2353: return "iload_2";
2354: case ByteCode.ILOAD_3:
2355: return "iload_3";
2356: case ByteCode.LLOAD_0:
2357: return "lload_0";
2358: case ByteCode.LLOAD_1:
2359: return "lload_1";
2360: case ByteCode.LLOAD_2:
2361: return "lload_2";
2362: case ByteCode.LLOAD_3:
2363: return "lload_3";
2364: case ByteCode.FLOAD_0:
2365: return "fload_0";
2366: case ByteCode.FLOAD_1:
2367: return "fload_1";
2368: case ByteCode.FLOAD_2:
2369: return "fload_2";
2370: case ByteCode.FLOAD_3:
2371: return "fload_3";
2372: case ByteCode.DLOAD_0:
2373: return "dload_0";
2374: case ByteCode.DLOAD_1:
2375: return "dload_1";
2376: case ByteCode.DLOAD_2:
2377: return "dload_2";
2378: case ByteCode.DLOAD_3:
2379: return "dload_3";
2380: case ByteCode.ALOAD_0:
2381: return "aload_0";
2382: case ByteCode.ALOAD_1:
2383: return "aload_1";
2384: case ByteCode.ALOAD_2:
2385: return "aload_2";
2386: case ByteCode.ALOAD_3:
2387: return "aload_3";
2388: case ByteCode.IALOAD:
2389: return "iaload";
2390: case ByteCode.LALOAD:
2391: return "laload";
2392: case ByteCode.FALOAD:
2393: return "faload";
2394: case ByteCode.DALOAD:
2395: return "daload";
2396: case ByteCode.AALOAD:
2397: return "aaload";
2398: case ByteCode.BALOAD:
2399: return "baload";
2400: case ByteCode.CALOAD:
2401: return "caload";
2402: case ByteCode.SALOAD:
2403: return "saload";
2404: case ByteCode.ISTORE:
2405: return "istore";
2406: case ByteCode.LSTORE:
2407: return "lstore";
2408: case ByteCode.FSTORE:
2409: return "fstore";
2410: case ByteCode.DSTORE:
2411: return "dstore";
2412: case ByteCode.ASTORE:
2413: return "astore";
2414: case ByteCode.ISTORE_0:
2415: return "istore_0";
2416: case ByteCode.ISTORE_1:
2417: return "istore_1";
2418: case ByteCode.ISTORE_2:
2419: return "istore_2";
2420: case ByteCode.ISTORE_3:
2421: return "istore_3";
2422: case ByteCode.LSTORE_0:
2423: return "lstore_0";
2424: case ByteCode.LSTORE_1:
2425: return "lstore_1";
2426: case ByteCode.LSTORE_2:
2427: return "lstore_2";
2428: case ByteCode.LSTORE_3:
2429: return "lstore_3";
2430: case ByteCode.FSTORE_0:
2431: return "fstore_0";
2432: case ByteCode.FSTORE_1:
2433: return "fstore_1";
2434: case ByteCode.FSTORE_2:
2435: return "fstore_2";
2436: case ByteCode.FSTORE_3:
2437: return "fstore_3";
2438: case ByteCode.DSTORE_0:
2439: return "dstore_0";
2440: case ByteCode.DSTORE_1:
2441: return "dstore_1";
2442: case ByteCode.DSTORE_2:
2443: return "dstore_2";
2444: case ByteCode.DSTORE_3:
2445: return "dstore_3";
2446: case ByteCode.ASTORE_0:
2447: return "astore_0";
2448: case ByteCode.ASTORE_1:
2449: return "astore_1";
2450: case ByteCode.ASTORE_2:
2451: return "astore_2";
2452: case ByteCode.ASTORE_3:
2453: return "astore_3";
2454: case ByteCode.IASTORE:
2455: return "iastore";
2456: case ByteCode.LASTORE:
2457: return "lastore";
2458: case ByteCode.FASTORE:
2459: return "fastore";
2460: case ByteCode.DASTORE:
2461: return "dastore";
2462: case ByteCode.AASTORE:
2463: return "aastore";
2464: case ByteCode.BASTORE:
2465: return "bastore";
2466: case ByteCode.CASTORE:
2467: return "castore";
2468: case ByteCode.SASTORE:
2469: return "sastore";
2470: case ByteCode.POP:
2471: return "pop";
2472: case ByteCode.POP2:
2473: return "pop2";
2474: case ByteCode.DUP:
2475: return "dup";
2476: case ByteCode.DUP_X1:
2477: return "dup_x1";
2478: case ByteCode.DUP_X2:
2479: return "dup_x2";
2480: case ByteCode.DUP2:
2481: return "dup2";
2482: case ByteCode.DUP2_X1:
2483: return "dup2_x1";
2484: case ByteCode.DUP2_X2:
2485: return "dup2_x2";
2486: case ByteCode.SWAP:
2487: return "swap";
2488: case ByteCode.IADD:
2489: return "iadd";
2490: case ByteCode.LADD:
2491: return "ladd";
2492: case ByteCode.FADD:
2493: return "fadd";
2494: case ByteCode.DADD:
2495: return "dadd";
2496: case ByteCode.ISUB:
2497: return "isub";
2498: case ByteCode.LSUB:
2499: return "lsub";
2500: case ByteCode.FSUB:
2501: return "fsub";
2502: case ByteCode.DSUB:
2503: return "dsub";
2504: case ByteCode.IMUL:
2505: return "imul";
2506: case ByteCode.LMUL:
2507: return "lmul";
2508: case ByteCode.FMUL:
2509: return "fmul";
2510: case ByteCode.DMUL:
2511: return "dmul";
2512: case ByteCode.IDIV:
2513: return "idiv";
2514: case ByteCode.LDIV:
2515: return "ldiv";
2516: case ByteCode.FDIV:
2517: return "fdiv";
2518: case ByteCode.DDIV:
2519: return "ddiv";
2520: case ByteCode.IREM:
2521: return "irem";
2522: case ByteCode.LREM:
2523: return "lrem";
2524: case ByteCode.FREM:
2525: return "frem";
2526: case ByteCode.DREM:
2527: return "drem";
2528: case ByteCode.INEG:
2529: return "ineg";
2530: case ByteCode.LNEG:
2531: return "lneg";
2532: case ByteCode.FNEG:
2533: return "fneg";
2534: case ByteCode.DNEG:
2535: return "dneg";
2536: case ByteCode.ISHL:
2537: return "ishl";
2538: case ByteCode.LSHL:
2539: return "lshl";
2540: case ByteCode.ISHR:
2541: return "ishr";
2542: case ByteCode.LSHR:
2543: return "lshr";
2544: case ByteCode.IUSHR:
2545: return "iushr";
2546: case ByteCode.LUSHR:
2547: return "lushr";
2548: case ByteCode.IAND:
2549: return "iand";
2550: case ByteCode.LAND:
2551: return "land";
2552: case ByteCode.IOR:
2553: return "ior";
2554: case ByteCode.LOR:
2555: return "lor";
2556: case ByteCode.IXOR:
2557: return "ixor";
2558: case ByteCode.LXOR:
2559: return "lxor";
2560: case ByteCode.IINC:
2561: return "iinc";
2562: case ByteCode.I2L:
2563: return "i2l";
2564: case ByteCode.I2F:
2565: return "i2f";
2566: case ByteCode.I2D:
2567: return "i2d";
2568: case ByteCode.L2I:
2569: return "l2i";
2570: case ByteCode.L2F:
2571: return "l2f";
2572: case ByteCode.L2D:
2573: return "l2d";
2574: case ByteCode.F2I:
2575: return "f2i";
2576: case ByteCode.F2L:
2577: return "f2l";
2578: case ByteCode.F2D:
2579: return "f2d";
2580: case ByteCode.D2I:
2581: return "d2i";
2582: case ByteCode.D2L:
2583: return "d2l";
2584: case ByteCode.D2F:
2585: return "d2f";
2586: case ByteCode.I2B:
2587: return "i2b";
2588: case ByteCode.I2C:
2589: return "i2c";
2590: case ByteCode.I2S:
2591: return "i2s";
2592: case ByteCode.LCMP:
2593: return "lcmp";
2594: case ByteCode.FCMPL:
2595: return "fcmpl";
2596: case ByteCode.FCMPG:
2597: return "fcmpg";
2598: case ByteCode.DCMPL:
2599: return "dcmpl";
2600: case ByteCode.DCMPG:
2601: return "dcmpg";
2602: case ByteCode.IFEQ:
2603: return "ifeq";
2604: case ByteCode.IFNE:
2605: return "ifne";
2606: case ByteCode.IFLT:
2607: return "iflt";
2608: case ByteCode.IFGE:
2609: return "ifge";
2610: case ByteCode.IFGT:
2611: return "ifgt";
2612: case ByteCode.IFLE:
2613: return "ifle";
2614: case ByteCode.IF_ICMPEQ:
2615: return "if_icmpeq";
2616: case ByteCode.IF_ICMPNE:
2617: return "if_icmpne";
2618: case ByteCode.IF_ICMPLT:
2619: return "if_icmplt";
2620: case ByteCode.IF_ICMPGE:
2621: return "if_icmpge";
2622: case ByteCode.IF_ICMPGT:
2623: return "if_icmpgt";
2624: case ByteCode.IF_ICMPLE:
2625: return "if_icmple";
2626: case ByteCode.IF_ACMPEQ:
2627: return "if_acmpeq";
2628: case ByteCode.IF_ACMPNE:
2629: return "if_acmpne";
2630: case ByteCode.GOTO:
2631: return "goto";
2632: case ByteCode.JSR:
2633: return "jsr";
2634: case ByteCode.RET:
2635: return "ret";
2636: case ByteCode.TABLESWITCH:
2637: return "tableswitch";
2638: case ByteCode.LOOKUPSWITCH:
2639: return "lookupswitch";
2640: case ByteCode.IRETURN:
2641: return "ireturn";
2642: case ByteCode.LRETURN:
2643: return "lreturn";
2644: case ByteCode.FRETURN:
2645: return "freturn";
2646: case ByteCode.DRETURN:
2647: return "dreturn";
2648: case ByteCode.ARETURN:
2649: return "areturn";
2650: case ByteCode.RETURN:
2651: return "return";
2652: case ByteCode.GETSTATIC:
2653: return "getstatic";
2654: case ByteCode.PUTSTATIC:
2655: return "putstatic";
2656: case ByteCode.GETFIELD:
2657: return "getfield";
2658: case ByteCode.PUTFIELD:
2659: return "putfield";
2660: case ByteCode.INVOKEVIRTUAL:
2661: return "invokevirtual";
2662: case ByteCode.INVOKESPECIAL:
2663: return "invokespecial";
2664: case ByteCode.INVOKESTATIC:
2665: return "invokestatic";
2666: case ByteCode.INVOKEINTERFACE:
2667: return "invokeinterface";
2668: case ByteCode.NEW:
2669: return "new";
2670: case ByteCode.NEWARRAY:
2671: return "newarray";
2672: case ByteCode.ANEWARRAY:
2673: return "anewarray";
2674: case ByteCode.ARRAYLENGTH:
2675: return "arraylength";
2676: case ByteCode.ATHROW:
2677: return "athrow";
2678: case ByteCode.CHECKCAST:
2679: return "checkcast";
2680: case ByteCode.INSTANCEOF:
2681: return "instanceof";
2682: case ByteCode.MONITORENTER:
2683: return "monitorenter";
2684: case ByteCode.MONITOREXIT:
2685: return "monitorexit";
2686: case ByteCode.WIDE:
2687: return "wide";
2688: case ByteCode.MULTIANEWARRAY:
2689: return "multianewarray";
2690: case ByteCode.IFNULL:
2691: return "ifnull";
2692: case ByteCode.IFNONNULL:
2693: return "ifnonnull";
2694: case ByteCode.GOTO_W:
2695: return "goto_w";
2696: case ByteCode.JSR_W:
2697: return "jsr_w";
2698: case ByteCode.BREAKPOINT:
2699: return "breakpoint";
2700:
2701: case ByteCode.IMPDEP1:
2702: return "impdep1";
2703: case ByteCode.IMPDEP2:
2704: return "impdep2";
2705: }
2706: }
2707: return "";
2708: }
2709:
2710: final char[] getCharBuffer(int minimalSize) {
2711: if (minimalSize > tmpCharBuffer.length) {
2712: int newSize = tmpCharBuffer.length * 2;
2713: if (minimalSize > newSize) {
2714: newSize = minimalSize;
2715: }
2716: tmpCharBuffer = new char[newSize];
2717: }
2718: return tmpCharBuffer;
2719: }
2720:
2721: private static final int LineNumberTableSize = 16;
2722: private static final int ExceptionTableSize = 4;
2723:
2724: private final static long FileHeaderConstant = 0xCAFEBABE0003002DL;
2725: // Set DEBUG flags to true to get better checking and progress info.
2726: private static final boolean DEBUGSTACK = false;
2727: private static final boolean DEBUGLABELS = false;
2728: private static final boolean DEBUGCODE = false;
2729:
2730: private String generatedClassName;
2731:
2732: private ExceptionTableEntry itsExceptionTable[];
2733: private int itsExceptionTableTop;
2734:
2735: private int itsLineNumberTable[]; // pack start_pc & line_number together
2736: private int itsLineNumberTableTop;
2737:
2738: private byte[] itsCodeBuffer = new byte[256];
2739: private int itsCodeBufferTop;
2740:
2741: private ConstantPool itsConstantPool;
2742:
2743: private ClassFileMethod itsCurrentMethod;
2744: private short itsStackTop;
2745:
2746: private short itsMaxStack;
2747: private short itsMaxLocals;
2748:
2749: private ObjArray itsMethods = new ObjArray();
2750: private ObjArray itsFields = new ObjArray();
2751: private ObjArray itsInterfaces = new ObjArray();
2752:
2753: private short itsFlags;
2754: private short itsThisClassIndex;
2755: private short itsSuperClassIndex;
2756: private short itsSourceFileNameIndex;
2757:
2758: private static final int MIN_LABEL_TABLE_SIZE = 32;
2759: private int[] itsLabelTable;
2760: private int itsLabelTableTop;
2761:
2762: // itsFixupTable[i] = (label_index << 32) | fixup_site
2763: private static final int MIN_FIXUP_TABLE_SIZE = 40;
2764: private long[] itsFixupTable;
2765: private int itsFixupTableTop;
2766: private ObjArray itsVarDescriptors;
2767:
2768: private char[] tmpCharBuffer = new char[64];
2769: }
2770:
2771: final class ExceptionTableEntry {
2772:
2773: ExceptionTableEntry(int startLabel, int endLabel, int handlerLabel,
2774: short catchType) {
2775: itsStartLabel = startLabel;
2776: itsEndLabel = endLabel;
2777: itsHandlerLabel = handlerLabel;
2778: itsCatchType = catchType;
2779: }
2780:
2781: int itsStartLabel;
2782: int itsEndLabel;
2783: int itsHandlerLabel;
2784: short itsCatchType;
2785: }
2786:
2787: final class ClassFileField {
2788:
2789: ClassFileField(short nameIndex, short typeIndex, short flags) {
2790: itsNameIndex = nameIndex;
2791: itsTypeIndex = typeIndex;
2792: itsFlags = flags;
2793: itsHasAttributes = false;
2794: }
2795:
2796: void setAttributes(short attr1, short attr2, short attr3, int index) {
2797: itsHasAttributes = true;
2798: itsAttr1 = attr1;
2799: itsAttr2 = attr2;
2800: itsAttr3 = attr3;
2801: itsIndex = index;
2802: }
2803:
2804: int write(byte[] data, int offset) {
2805: offset = ClassFileWriter.putInt16(itsFlags, data, offset);
2806: offset = ClassFileWriter.putInt16(itsNameIndex, data, offset);
2807: offset = ClassFileWriter.putInt16(itsTypeIndex, data, offset);
2808: if (!itsHasAttributes) {
2809: // write 0 attributes
2810: offset = ClassFileWriter.putInt16(0, data, offset);
2811: } else {
2812: offset = ClassFileWriter.putInt16(1, data, offset);
2813: offset = ClassFileWriter.putInt16(itsAttr1, data, offset);
2814: offset = ClassFileWriter.putInt16(itsAttr2, data, offset);
2815: offset = ClassFileWriter.putInt16(itsAttr3, data, offset);
2816: offset = ClassFileWriter.putInt16(itsIndex, data, offset);
2817: }
2818: return offset;
2819: }
2820:
2821: int getWriteSize() {
2822: int size = 2 * 3;
2823: if (!itsHasAttributes) {
2824: size += 2;
2825: } else {
2826: size += 2 + 2 * 4;
2827: }
2828: return size;
2829: }
2830:
2831: private short itsNameIndex;
2832: private short itsTypeIndex;
2833: private short itsFlags;
2834: private boolean itsHasAttributes;
2835: private short itsAttr1, itsAttr2, itsAttr3;
2836: private int itsIndex;
2837: }
2838:
2839: final class ClassFileMethod {
2840:
2841: ClassFileMethod(short nameIndex, short typeIndex, short flags) {
2842: itsNameIndex = nameIndex;
2843: itsTypeIndex = typeIndex;
2844: itsFlags = flags;
2845: }
2846:
2847: void setCodeAttribute(byte codeAttribute[]) {
2848: itsCodeAttribute = codeAttribute;
2849: }
2850:
2851: int write(byte[] data, int offset) {
2852: offset = ClassFileWriter.putInt16(itsFlags, data, offset);
2853: offset = ClassFileWriter.putInt16(itsNameIndex, data, offset);
2854: offset = ClassFileWriter.putInt16(itsTypeIndex, data, offset);
2855: // Code attribute only
2856: offset = ClassFileWriter.putInt16(1, data, offset);
2857: System.arraycopy(itsCodeAttribute, 0, data, offset,
2858: itsCodeAttribute.length);
2859: offset += itsCodeAttribute.length;
2860: return offset;
2861: }
2862:
2863: int getWriteSize() {
2864: return 2 * 4 + itsCodeAttribute.length;
2865: }
2866:
2867: private short itsNameIndex;
2868: private short itsTypeIndex;
2869: private short itsFlags;
2870: private byte[] itsCodeAttribute;
2871:
2872: }
2873:
2874: final class ConstantPool {
2875:
2876: ConstantPool(ClassFileWriter cfw) {
2877: this .cfw = cfw;
2878: itsTopIndex = 1; // the zero'th entry is reserved
2879: itsPool = new byte[ConstantPoolSize];
2880: itsTop = 0;
2881: }
2882:
2883: private static final int ConstantPoolSize = 256;
2884: private static final byte CONSTANT_Class = 7,
2885: CONSTANT_Fieldref = 9, CONSTANT_Methodref = 10,
2886: CONSTANT_InterfaceMethodref = 11, CONSTANT_String = 8,
2887: CONSTANT_Integer = 3, CONSTANT_Float = 4,
2888: CONSTANT_Long = 5, CONSTANT_Double = 6,
2889: CONSTANT_NameAndType = 12, CONSTANT_Utf8 = 1;
2890:
2891: int write(byte[] data, int offset) {
2892: offset = ClassFileWriter.putInt16((short) itsTopIndex, data,
2893: offset);
2894: System.arraycopy(itsPool, 0, data, offset, itsTop);
2895: offset += itsTop;
2896: return offset;
2897: }
2898:
2899: int getWriteSize() {
2900: return 2 + itsTop;
2901: }
2902:
2903: int addConstant(int k) {
2904: ensure(5);
2905: itsPool[itsTop++] = CONSTANT_Integer;
2906: itsTop = ClassFileWriter.putInt32(k, itsPool, itsTop);
2907: return (short) (itsTopIndex++);
2908: }
2909:
2910: int addConstant(long k) {
2911: ensure(9);
2912: itsPool[itsTop++] = CONSTANT_Long;
2913: itsTop = ClassFileWriter.putInt64(k, itsPool, itsTop);
2914: int index = itsTopIndex;
2915: itsTopIndex += 2;
2916: return index;
2917: }
2918:
2919: int addConstant(float k) {
2920: ensure(5);
2921: itsPool[itsTop++] = CONSTANT_Float;
2922: int bits = Float.floatToIntBits(k);
2923: itsTop = ClassFileWriter.putInt32(bits, itsPool, itsTop);
2924: return itsTopIndex++;
2925: }
2926:
2927: int addConstant(double k) {
2928: ensure(9);
2929: itsPool[itsTop++] = CONSTANT_Double;
2930: long bits = Double.doubleToLongBits(k);
2931: itsTop = ClassFileWriter.putInt64(bits, itsPool, itsTop);
2932: int index = itsTopIndex;
2933: itsTopIndex += 2;
2934: return index;
2935: }
2936:
2937: int addConstant(String k) {
2938: int utf8Index = 0xFFFF & addUtf8(k);
2939: int theIndex = itsStringConstHash.getInt(utf8Index, -1);
2940: if (theIndex == -1) {
2941: theIndex = itsTopIndex++;
2942: ensure(3);
2943: itsPool[itsTop++] = CONSTANT_String;
2944: itsTop = ClassFileWriter.putInt16(utf8Index, itsPool,
2945: itsTop);
2946: itsStringConstHash.put(utf8Index, theIndex);
2947: }
2948: return theIndex;
2949: }
2950:
2951: boolean isUnderUtfEncodingLimit(String s) {
2952: int strLen = s.length();
2953: if (strLen * 3 <= MAX_UTF_ENCODING_SIZE) {
2954: return true;
2955: } else if (strLen > MAX_UTF_ENCODING_SIZE) {
2956: return false;
2957: }
2958: return strLen == getUtfEncodingLimit(s, 0, strLen);
2959: }
2960:
2961: /**
2962: * Get maximum i such that <tt>start <= i <= end</tt> and
2963: * <tt>s.substring(start, i)</tt> fits JVM UTF string encoding limit.
2964: */
2965: int getUtfEncodingLimit(String s, int start, int end) {
2966: if ((end - start) * 3 <= MAX_UTF_ENCODING_SIZE) {
2967: return end;
2968: }
2969: int limit = MAX_UTF_ENCODING_SIZE;
2970: for (int i = start; i != end; i++) {
2971: int c = s.charAt(i);
2972: if (0 != c && c <= 0x7F) {
2973: --limit;
2974: } else if (c < 0x7FF) {
2975: limit -= 2;
2976: } else {
2977: limit -= 3;
2978: }
2979: if (limit < 0) {
2980: return i;
2981: }
2982: }
2983: return end;
2984: }
2985:
2986: short addUtf8(String k) {
2987: int theIndex = itsUtf8Hash.get(k, -1);
2988: if (theIndex == -1) {
2989: int strLen = k.length();
2990: boolean tooBigString;
2991: if (strLen > MAX_UTF_ENCODING_SIZE) {
2992: tooBigString = true;
2993: } else {
2994: tooBigString = false;
2995: // Ask for worst case scenario buffer when each char takes 3
2996: // bytes
2997: ensure(1 + 2 + strLen * 3);
2998: int top = itsTop;
2999:
3000: itsPool[top++] = CONSTANT_Utf8;
3001: top += 2; // skip length
3002:
3003: char[] chars = cfw.getCharBuffer(strLen);
3004: k.getChars(0, strLen, chars, 0);
3005:
3006: for (int i = 0; i != strLen; i++) {
3007: int c = chars[i];
3008: if (c != 0 && c <= 0x7F) {
3009: itsPool[top++] = (byte) c;
3010: } else if (c > 0x7FF) {
3011: itsPool[top++] = (byte) (0xE0 | (c >> 12));
3012: itsPool[top++] = (byte) (0x80 | ((c >> 6) & 0x3F));
3013: itsPool[top++] = (byte) (0x80 | (c & 0x3F));
3014: } else {
3015: itsPool[top++] = (byte) (0xC0 | (c >> 6));
3016: itsPool[top++] = (byte) (0x80 | (c & 0x3F));
3017: }
3018: }
3019:
3020: int utfLen = top - (itsTop + 1 + 2);
3021: if (utfLen > MAX_UTF_ENCODING_SIZE) {
3022: tooBigString = true;
3023: } else {
3024: // Write back length
3025: itsPool[itsTop + 1] = (byte) (utfLen >>> 8);
3026: itsPool[itsTop + 2] = (byte) utfLen;
3027:
3028: itsTop = top;
3029: theIndex = itsTopIndex++;
3030: itsUtf8Hash.put(k, theIndex);
3031: }
3032: }
3033: if (tooBigString) {
3034: throw new IllegalArgumentException("Too big string");
3035: }
3036: }
3037: return (short) theIndex;
3038: }
3039:
3040: private short addNameAndType(String name, String type) {
3041: short nameIndex = addUtf8(name);
3042: short typeIndex = addUtf8(type);
3043: ensure(5);
3044: itsPool[itsTop++] = CONSTANT_NameAndType;
3045: itsTop = ClassFileWriter.putInt16(nameIndex, itsPool, itsTop);
3046: itsTop = ClassFileWriter.putInt16(typeIndex, itsPool, itsTop);
3047: return (short) (itsTopIndex++);
3048: }
3049:
3050: short addClass(String className) {
3051: int theIndex = itsClassHash.get(className, -1);
3052: if (theIndex == -1) {
3053: String slashed = className;
3054: if (className.indexOf('.') > 0) {
3055: slashed = ClassFileWriter.getSlashedForm(className);
3056: theIndex = itsClassHash.get(slashed, -1);
3057: if (theIndex != -1) {
3058: itsClassHash.put(className, theIndex);
3059: }
3060: }
3061: if (theIndex == -1) {
3062: int utf8Index = addUtf8(slashed);
3063: ensure(3);
3064: itsPool[itsTop++] = CONSTANT_Class;
3065: itsTop = ClassFileWriter.putInt16(utf8Index, itsPool,
3066: itsTop);
3067: theIndex = itsTopIndex++;
3068: itsClassHash.put(slashed, theIndex);
3069: if (className != slashed) {
3070: itsClassHash.put(className, theIndex);
3071: }
3072: }
3073: }
3074: return (short) theIndex;
3075: }
3076:
3077: short addFieldRef(String className, String fieldName,
3078: String fieldType) {
3079: FieldOrMethodRef ref = new FieldOrMethodRef(className,
3080: fieldName, fieldType);
3081:
3082: int theIndex = itsFieldRefHash.get(ref, -1);
3083: if (theIndex == -1) {
3084: short ntIndex = addNameAndType(fieldName, fieldType);
3085: short classIndex = addClass(className);
3086: ensure(5);
3087: itsPool[itsTop++] = CONSTANT_Fieldref;
3088: itsTop = ClassFileWriter.putInt16(classIndex, itsPool,
3089: itsTop);
3090: itsTop = ClassFileWriter.putInt16(ntIndex, itsPool, itsTop);
3091: theIndex = itsTopIndex++;
3092: itsFieldRefHash.put(ref, theIndex);
3093: }
3094: return (short) theIndex;
3095: }
3096:
3097: short addMethodRef(String className, String methodName,
3098: String methodType) {
3099: FieldOrMethodRef ref = new FieldOrMethodRef(className,
3100: methodName, methodType);
3101:
3102: int theIndex = itsMethodRefHash.get(ref, -1);
3103: if (theIndex == -1) {
3104: short ntIndex = addNameAndType(methodName, methodType);
3105: short classIndex = addClass(className);
3106: ensure(5);
3107: itsPool[itsTop++] = CONSTANT_Methodref;
3108: itsTop = ClassFileWriter.putInt16(classIndex, itsPool,
3109: itsTop);
3110: itsTop = ClassFileWriter.putInt16(ntIndex, itsPool, itsTop);
3111: theIndex = itsTopIndex++;
3112: itsMethodRefHash.put(ref, theIndex);
3113: }
3114: return (short) theIndex;
3115: }
3116:
3117: short addInterfaceMethodRef(String className, String methodName,
3118: String methodType) {
3119: short ntIndex = addNameAndType(methodName, methodType);
3120: short classIndex = addClass(className);
3121: ensure(5);
3122: itsPool[itsTop++] = CONSTANT_InterfaceMethodref;
3123: itsTop = ClassFileWriter.putInt16(classIndex, itsPool, itsTop);
3124: itsTop = ClassFileWriter.putInt16(ntIndex, itsPool, itsTop);
3125: return (short) (itsTopIndex++);
3126: }
3127:
3128: void ensure(int howMuch) {
3129: if (itsTop + howMuch > itsPool.length) {
3130: int newCapacity = itsPool.length * 2;
3131: if (itsTop + howMuch > newCapacity) {
3132: newCapacity = itsTop + howMuch;
3133: }
3134: byte[] tmp = new byte[newCapacity];
3135: System.arraycopy(itsPool, 0, tmp, 0, itsTop);
3136: itsPool = tmp;
3137: }
3138: }
3139:
3140: private ClassFileWriter cfw;
3141:
3142: private static final int MAX_UTF_ENCODING_SIZE = 65535;
3143:
3144: private UintMap itsStringConstHash = new UintMap();
3145: private ObjToIntMap itsUtf8Hash = new ObjToIntMap();
3146: private ObjToIntMap itsFieldRefHash = new ObjToIntMap();
3147: private ObjToIntMap itsMethodRefHash = new ObjToIntMap();
3148: private ObjToIntMap itsClassHash = new ObjToIntMap();
3149:
3150: private int itsTop;
3151: private int itsTopIndex;
3152: private byte itsPool[];
3153: }
3154:
3155: final class FieldOrMethodRef {
3156: FieldOrMethodRef(String className, String name, String type) {
3157: this .className = className;
3158: this .name = name;
3159: this .type = type;
3160: }
3161:
3162: public boolean equals(Object obj) {
3163: if (!(obj instanceof FieldOrMethodRef)) {
3164: return false;
3165: }
3166: FieldOrMethodRef x = (FieldOrMethodRef) obj;
3167: return className.equals(x.className) && name.equals(x.name)
3168: && type.equals(x.type);
3169: }
3170:
3171: public int hashCode() {
3172: if (hashCode == -1) {
3173: int h1 = className.hashCode();
3174: int h2 = name.hashCode();
3175: int h3 = type.hashCode();
3176: hashCode = h1 ^ h2 ^ h3;
3177: }
3178: return hashCode;
3179: }
3180:
3181: private String className;
3182: private String name;
3183: private String type;
3184: private int hashCode = -1;
3185: }
|