0001: /*
0002: * @(#)ClassFile.java 1.6 05/06/27
0003: *
0004: * Copyright (c) 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
0005: *
0006: * See the file "LICENSE.txt" for information on usage and redistribution
0007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
0008: */
0009: package pnuts.compiler;
0010:
0011: import java.io.DataOutputStream;
0012: import java.io.IOException;
0013: import java.io.OutputStream;
0014: import java.util.Enumeration;
0015: import java.util.ArrayList;
0016: import java.util.List;
0017:
0018: /**
0019: * This class provides a way of making Java class file image.
0020: */
0021: public class ClassFile {
0022:
0023: private final static long MAGIC = 0xcafebabe0003002dL;
0024:
0025: private final static boolean DEBUG = false;
0026:
0027: /**
0028: * The effect on the operand stack of a given opcode.
0029: */
0030: static final byte[] stackGrowth = { 0, // nop
0031: 1, // aconst_null
0032: 1, // iconst_m1
0033: 1, // iconst_0
0034: 1, // iconst_1
0035: 1, // iconst_2
0036: 1, // iconst_3
0037: 1, // iconst_4
0038: 1, // iconst_5
0039: 2, // lconst_0
0040: 2, // lconst_1
0041: 1, // fconst_0
0042: 1, // fconst_1
0043: 1, // fconst_2
0044: 2, // dconst_0
0045: 2, // dconst_1
0046: 1, // bipush
0047: 1, // sipush
0048: 1, // ldc
0049: 1, // ldc_W
0050: 2, // ldc2_W
0051: 1, // iload
0052: 2, // lload
0053: 1, // fload
0054: 2, // dload
0055: 1, // aload
0056: 1, // iload_0
0057: 1, // iload_1
0058: 1, // iload_2
0059: 1, // iload_3
0060: 2, // lload_0
0061: 2, // lload_1
0062: 2, // lload_2
0063: 2, // lload_3
0064: 1, // fload_0
0065: 1, // fload_1
0066: 1, // fload_2
0067: 1, // fload_3
0068: 2, // dload_0
0069: 2, // dload_1
0070: 2, // dload_2
0071: 2, // dload_3
0072: 1, // aload_0
0073: 1, // aload_1
0074: 1, // aload_2
0075: 1, // aload_3
0076: -1, // iaload
0077: 0, // laload
0078: -1, // faload
0079: 0, // daload
0080: -1, // aaload
0081: -1, // baload
0082: -1, // caload
0083: -1, // saload
0084: -1, // istore
0085: -2, // lstore
0086: -1, // fstore
0087: -2, // dstore
0088: -1, // astore
0089: -1, // istore_0
0090: -1, // istore_1
0091: -1, // istore_2
0092: -1, // istore_3
0093: -2, // lstore_0
0094: -2, // lstore_1
0095: -2, // lstore_2
0096: -2, // lstore_3
0097: -1, // fstore_0
0098: -1, // fstore_1
0099: -1, // fstore_2
0100: -1, // fstore_3
0101: -2, // dstore_0
0102: -2, // dstore_1
0103: -2, // dstore_2
0104: -2, // dstore_3
0105: -1, // astore_0
0106: -1, // astore_1
0107: -1, // astore_2
0108: -1, // astore_3
0109: -3, // iastore
0110: -4, // lastore
0111: -3, // fastore
0112: -4, // dastore
0113: -3, // aastore
0114: -3, // bastore
0115: -3, // castore
0116: -3, // sastore
0117: -1, // pop
0118: -2, // pop2
0119: 1, // dup
0120: 1, // dup_X1
0121: 1, // dup_X2
0122: 2, // dup2
0123: 2, // dup2_X1
0124: 2, // dup2_X2
0125: 0, // swap
0126: -1, // iadd
0127: -2, // ladd
0128: -1, // fadd
0129: -2, // dadd
0130: -1, // isub
0131: -2, // lsub
0132: -1, // fsub
0133: -2, // dsub
0134: -1, // imul
0135: -2, // lmul
0136: -1, // fmul
0137: -2, // dmul
0138: -1, // idiv
0139: -2, // ldiv
0140: -1, // fdiv
0141: -2, // ddiv
0142: -1, // irem
0143: -2, // lrem
0144: -1, // frem
0145: -2, // drem
0146: 0, // ineg
0147: 0, // lneg
0148: 0, // fneg
0149: 0, // dneg
0150: -1, // ishl
0151: -1, // lshl
0152: -1, // ishr
0153: -1, // lshr
0154: -1, // iushr
0155: -1, // lushr
0156: -1, // iand
0157: -2, // land
0158: -1, // ior
0159: -2, // lor
0160: -1, // ixor
0161: -2, // lxor
0162: 0, // iinc
0163: 1, // i2l
0164: 0, // i2f
0165: 1, // i2d
0166: -1, // l2i
0167: -1, // l2f
0168: 0, // l2d
0169: 0, // f2i
0170: 1, // f2l
0171: 1, // f2d
0172: -1, // d2i
0173: 0, // d2l
0174: -1, // d2f
0175: 0, // i2b
0176: 0, // i2c
0177: 0, // i2s
0178: -3, // lcmp
0179: -1, // fcmpl
0180: -1, // fcmpg
0181: -3, // dcmpl
0182: -3, // dcmpg
0183: -1, // ifeq
0184: -1, // ifne
0185: -1, // iflt
0186: -1, // ifge
0187: -1, // ifgt
0188: -1, // ifle
0189: -2, // if_icmpeq
0190: -2, // if_icmpne
0191: -2, // if_icmplt
0192: -2, // if_icmpge
0193: -2, // if_icmpgt
0194: -2, // if_icmple
0195: -2, // if_acmpeq
0196: -2, // if_acmpne
0197: 0, // goto
0198: 0, // jsr
0199: 0, // ret
0200: -1, // tableswitch
0201: -1, // lookupswitch
0202: -1, // ireturn
0203: -2, // lreturn
0204: -1, // freturn
0205: -2, // dreturn
0206: -1, // areturn
0207: 0, // return
0208: 0, // getstatic
0209: 0, // putstatic
0210: -1, // getfield
0211: -1, // putfield
0212: -1, // invokevirtual
0213: -1, // invokespecial
0214: 0, // invokestatic
0215: -1, // invokeinterface
0216: 0, // UNUSED
0217: 1, // new
0218: 0, // newarray
0219: 0, // anewarray
0220: 0, // arraylength
0221: -1, // athrow
0222: 0, // checkcast
0223: 0, // instanceof
0224: -1, // monitorenter
0225: -1, // monitorexit
0226: 0, // wide
0227: 1, // multianewarray
0228: -1, // ifnull
0229: -1, // ifnonnull
0230: 0, // goto_w
0231: 1, // jsr_w
0232: 0, // breakpoint
0233: 1, // ldc_quick
0234: 1, // ldc_w_quick
0235: 2, // ldc2_w_quick
0236: 0, // getfield_quick
0237: 0, // putfield_quick
0238: 0, // getfield2_quick
0239: 0, // putfield2_quick
0240: 0, // getstatic_quick
0241: 0, // putstatic_quick
0242: 0, // getstatic2_quick
0243: 0, // putstatic2_quick
0244: 0, // invokevirtual_quick
0245: 0, // invokenonvirtual_quick
0246: 0, // invokesuper_quick
0247: 0, // invokestatic_quick
0248: 0, // invokeinterface_quick
0249: 0, // invokevirtualobject_quick
0250: 0, // UNUSED
0251: 1, // new_quick
0252: 1, // anewarray_quick
0253: 1, // multianewarray_quick
0254: -1, // checkcast_quick
0255: 0, // instanceof_quick
0256: 0, // invokevirtual_quick_w
0257: 0, // getfield_quick_w
0258: 0 // putfield_quick_w
0259: };
0260:
0261: private ConstantPool constantPool;
0262:
0263: private List methods = new ArrayList(); // MethodInfo
0264:
0265: private MethodInfo currentMethod;
0266:
0267: private List fields = new ArrayList(); // FieldInfo
0268:
0269: private List exceptionTable;
0270:
0271: private List interfaces = new ArrayList();
0272:
0273: private short this ClassIndex;
0274:
0275: private short super ClassIndex;
0276:
0277: private short sourceFileNameIndex;
0278:
0279: private short accessFlags;
0280:
0281: private short maxStack;
0282:
0283: private short stackTop;
0284:
0285: private boolean locals[];
0286:
0287: public ClassFile parent;
0288:
0289: private String className;
0290:
0291: private int maxLocal;
0292:
0293: ByteBuffer codeBuffer;
0294:
0295: public ClassFile(String this Class, String super Class,
0296: String sourceFile, short accessFlags) {
0297:
0298: constantPool = new ConstantPool();
0299: this ClassIndex = constantPool.addClass(this Class);
0300: super ClassIndex = constantPool.addClass(super Class);
0301: if (sourceFile != null) {
0302: sourceFileNameIndex = constantPool.addUTF8(sourceFile);
0303: }
0304: this .accessFlags = accessFlags;
0305: this .className = this Class;
0306: }
0307:
0308: public String getClassName() {
0309: return className;
0310: }
0311:
0312: public void setCodeBuffer(ByteBuffer cbuf) {
0313: this .codeBuffer = cbuf;
0314: }
0315:
0316: public ByteBuffer getCodeBuffer() {
0317: return codeBuffer;
0318: }
0319:
0320: public int codeSize() {
0321: return codeBuffer.size();
0322: }
0323:
0324: public void addInterface(String interfaceName) {
0325: interfaces.add(new Short(constantPool.addClass(interfaceName)));
0326: }
0327:
0328: public void addField(String fieldName, String type,
0329: short accessFlags) {
0330: fields.add(new FieldInfo(constantPool.addUTF8(fieldName),
0331: constantPool.addUTF8(type), accessFlags));
0332: }
0333:
0334: public short addConstant(String value) {
0335: return constantPool.addConstant(value);
0336: }
0337:
0338: public void addConstant(String fieldName, String type, short flags,
0339: short valueIndex) {
0340: short fieldNameIndex = constantPool.addUTF8(fieldName);
0341: short typeIndex = constantPool.addUTF8(type);
0342: short cvAttr[] = new short[4];
0343: cvAttr[0] = constantPool.addUTF8("ConstantValue");
0344: cvAttr[1] = 0;
0345: cvAttr[2] = 2;
0346: cvAttr[3] = valueIndex;
0347: fields.add(new FieldInfo(fieldNameIndex, typeIndex, flags,
0348: cvAttr));
0349: }
0350:
0351: public void addConstant(String fieldName, String type, short flags,
0352: int value) {
0353: addConstant(fieldName, type, flags, constantPool
0354: .addConstant(value));
0355: }
0356:
0357: public void addConstant(String fieldName, String type, short flags,
0358: long value) {
0359: addConstant(fieldName, type, flags, constantPool
0360: .addConstant(value));
0361: }
0362:
0363: public void addConstant(String fieldName, String type, short flags,
0364: double value) {
0365: addConstant(fieldName, type, flags, constantPool
0366: .addConstant(value));
0367: }
0368:
0369: public void addConstant(String fieldName, String type, short flags,
0370: String value) {
0371: addConstant(fieldName, type, flags, constantPool
0372: .addConstant(value));
0373: }
0374:
0375: public void openMethod(String methodName, String type, short flag) {
0376: openMethod(methodName, type, flag, null);
0377: }
0378:
0379: public void openMethod(String methodName, String type, short flag,
0380: String[] exceptions) {
0381: codeBuffer = new ByteBuffer();
0382: int sig = sizeOfParameters(type);
0383: int nlocals = sig & 0xff;
0384: if ((flag & Constants.ACC_STATIC) != Constants.ACC_STATIC) {
0385: nlocals++;
0386: }
0387:
0388: locals = new boolean[nlocals + 32];
0389: for (int i = 0; i < nlocals; i++) {
0390: this .locals[i] = true;
0391: }
0392: maxLocal = nlocals;
0393:
0394: ExceptionAttr exceptionAttr = null;
0395: if (exceptions != null) {
0396: short exceptionAttributeIndex = constantPool
0397: .addUTF8("Exceptions");
0398: short[] e = new short[exceptions.length];
0399: for (int i = 0; i < exceptions.length; i++) {
0400: e[i] = constantPool.addClass(exceptions[i]);
0401: }
0402: exceptionAttr = new ExceptionAttr(exceptionAttributeIndex,
0403: e);
0404: }
0405: currentMethod = new MethodInfo(
0406: constantPool.addUTF8(methodName), constantPool
0407: .addUTF8(type), flag, exceptionAttr);
0408: methods.add(currentMethod);
0409: }
0410:
0411: public void closeMethod() {
0412: if ((currentMethod.accessFlags & Constants.ACC_ABSTRACT) == Constants.ACC_ABSTRACT) {
0413: return;
0414: }
0415: int codeSize = codeSize();
0416: if (DEBUG) {
0417: System.out.println("codeSize = " + codeSize);
0418: }
0419: if (codeSize > 65535) {
0420: throw new ClassFormatError("code size is too large "
0421: + codeSize);
0422: }
0423: int exceptionSize = 0;
0424: if (exceptionTable != null) {
0425: exceptionSize = exceptionTable.size();
0426: }
0427: LineNumberTable lineNumberTable = currentMethod.lineNumberTable;
0428: int lineNumberSize = 0;
0429: if (lineNumberTable != null) {
0430: lineNumberSize = 8 + 4 * lineNumberTable.size();
0431: }
0432:
0433: int attrLength = 2 + // attribute_name_index
0434: 4 + // attribute_length
0435: 2 + // max_stack
0436: 2 + // max_locals
0437: 4 + // code_length
0438: codeSize + 2 + // exception_table_length
0439: (exceptionSize * 8) + 2 + // attributes_count
0440: lineNumberSize; // LineNumberTable
0441:
0442: ByteBuffer codeAttr = new ByteBuffer(attrLength);
0443: int codeAttrIndex = constantPool.addUTF8("Code");
0444: codeAttr.add((short) codeAttrIndex);
0445:
0446: int attr_len = attrLength - 6;
0447: codeAttr.add(attr_len);
0448: codeAttr.add((short) maxStack);
0449: codeAttr.add((short) maxLocal);
0450:
0451: codeAttr.add(codeSize);
0452: codeAttr.append(codeBuffer);
0453:
0454: if (exceptionSize > 0) {
0455: codeAttr.add((short) exceptionTable.size());
0456: for (int i = 0, n = exceptionTable.size(); i < n; i++) {
0457: ExceptionTableEntry entry = (ExceptionTableEntry) exceptionTable
0458: .get(i);
0459: codeAttr.add(entry.start.getPC());
0460: codeAttr.add(entry.end.getPC());
0461: codeAttr.add(entry.handler.getPC());
0462: codeAttr.add(entry.catchType);
0463: }
0464: /*
0465: for (Enumeration e = exceptionTable.elements(); e.hasMoreElements();) {
0466: ExceptionTableEntry entry = (ExceptionTableEntry) e
0467: .nextElement();
0468: codeAttr.add(entry.start.getPC());
0469: codeAttr.add(entry.end.getPC());
0470: codeAttr.add(entry.handler.getPC());
0471: codeAttr.add(entry.catchType);
0472: }
0473: */
0474: } else {
0475: codeAttr.add((short) 0);
0476: }
0477:
0478: if (lineNumberTable != null) {
0479: codeAttr.add((short) 1);
0480: } else {
0481: codeAttr.add((short) 0);
0482: }
0483:
0484: currentMethod.setCodeAttribute(codeAttr);
0485:
0486: exceptionTable = null;
0487: codeBuffer.setSize(0);
0488: currentMethod = null;
0489: maxStack = 0;
0490: maxLocal = 0;
0491: stackTop = 0;
0492: }
0493:
0494: public void shift(int offset) {
0495: if (exceptionTable != null) {
0496: for (int i = 0, n = exceptionTable.size(); i < n; i++) {
0497: ExceptionTableEntry entry = (ExceptionTableEntry) exceptionTable
0498: .get(i);
0499: entry.start = entry.start.shift(offset);
0500: entry.end = entry.end.shift(offset);
0501: entry.handler = entry.handler.shift(offset);
0502: }
0503: }
0504: LineNumberTable lineNumberTable = this .currentMethod.lineNumberTable;
0505: if (lineNumberTable != null) {
0506: lineNumberTable.shift(offset);
0507: }
0508: }
0509:
0510: void updateStack(byte opcode) {
0511: int idx = opcode & 0xff;
0512: int growth = stackGrowth[idx];
0513: stackTop += growth;
0514: if (stackTop > maxStack) {
0515: maxStack = stackTop;
0516: }
0517: }
0518:
0519: public void popStack() {
0520: --stackTop;
0521: }
0522:
0523: public void add(byte opcode) {
0524: codeBuffer.add(opcode);
0525: updateStack(opcode);
0526: }
0527:
0528: public void addByte(byte val) {
0529: codeBuffer.add(val);
0530: }
0531:
0532: public void addInt(int ival) {
0533: codeBuffer.add((byte) ((ival >> 24) & 0xff));
0534: codeBuffer.add((byte) ((ival >> 16) & 0xff));
0535: codeBuffer.add((byte) ((ival >> 8) & 0xff));
0536: codeBuffer.add((byte) ((ival >> 0) & 0xff));
0537: }
0538:
0539: public Label getLabel() {
0540: return getLabel(false);
0541: }
0542:
0543: public Label getLabel(boolean fixed) {
0544: Label label = new Label(this );
0545: if (fixed) {
0546: label.fix();
0547: }
0548: return label;
0549: }
0550:
0551: public int declareLocal() {
0552: if (maxLocal >= locals.length) {
0553: boolean[] new_locals = new boolean[locals.length * 2];
0554: System.arraycopy(locals, 0, new_locals, 0, locals.length);
0555: locals = new_locals;
0556: }
0557: locals[maxLocal] = true;
0558: return maxLocal++;
0559: }
0560:
0561: public int getLocal() {
0562: for (int i = 0; i < maxLocal; i++) {
0563: if (!locals[i]) {
0564: locals[i] = true;
0565: return i;
0566: }
0567: }
0568: if (maxLocal >= locals.length) {
0569: boolean[] new_locals = new boolean[locals.length * 2];
0570: System.arraycopy(locals, 0, new_locals, 0, locals.length);
0571: locals = new_locals;
0572: }
0573: locals[maxLocal] = true;
0574: return maxLocal++;
0575: }
0576:
0577: public void freeLocal(int index) {
0578: locals[index] = false;
0579: }
0580:
0581: public void istoreLocal(int index) {
0582: if (index >= 0 && index < 4) {
0583: add((byte) (Opcode.ISTORE_0 + index));
0584: } else {
0585: add(Opcode.ISTORE, index);
0586: }
0587: }
0588:
0589: public void iloadLocal(int index) {
0590: if (index >= 0 && index < 4) {
0591: add((byte) (Opcode.ILOAD_0 + index));
0592: } else {
0593: add(Opcode.ILOAD, index);
0594: }
0595: }
0596:
0597: public void lloadLocal(int index) {
0598: if (index >= 0 && index < 4) {
0599: add((byte) (Opcode.LLOAD_0 + index));
0600: } else {
0601: add(Opcode.LLOAD, index);
0602: }
0603: }
0604:
0605: public void floadLocal(int index) {
0606: if (index >= 0 && index < 4) {
0607: add((byte) (Opcode.FLOAD_0 + index));
0608: } else {
0609: add(Opcode.FLOAD, index);
0610: }
0611: }
0612:
0613: public void dloadLocal(int index) {
0614: if (index >= 0 && index < 4) {
0615: add((byte) (Opcode.DLOAD_0 + index));
0616: } else {
0617: add(Opcode.DLOAD, index);
0618: }
0619: }
0620:
0621: public void loadLocal(int index) {
0622: if (index >= 0 && index < 4) {
0623: add((byte) (Opcode.ALOAD_0 + index));
0624: } else {
0625: add(Opcode.ALOAD, index);
0626: }
0627: }
0628:
0629: public void storeLocal(int index) {
0630: if (index >= 0 && index < 4) {
0631: add((byte) (Opcode.ASTORE_0 + index));
0632: } else {
0633: add(Opcode.ASTORE, index);
0634: }
0635: }
0636:
0637: public void add(byte opcode, Label label) {
0638: switch (opcode) {
0639: case Opcode.GOTO: // fall-through
0640: case Opcode.IFEQ:
0641: case Opcode.IFNE:
0642: case Opcode.IFLT:
0643: case Opcode.IFGE:
0644: case Opcode.IFGT:
0645: case Opcode.IFLE:
0646: case Opcode.IF_ICMPEQ:
0647: case Opcode.IF_ICMPNE:
0648: case Opcode.IF_ICMPLT:
0649: case Opcode.IF_ICMPGE:
0650: case Opcode.IF_ICMPGT:
0651: case Opcode.IF_ICMPLE:
0652: case Opcode.IF_ACMPEQ:
0653: case Opcode.IF_ACMPNE:
0654: case Opcode.JSR:
0655: case Opcode.IFNULL:
0656: case Opcode.IFNONNULL:
0657: int pc = codeBuffer.size();
0658: codeBuffer.add(opcode);
0659: label.register(pc, 2);
0660: int growth = stackGrowth[opcode & 0xff];
0661: stackTop += growth;
0662: break;
0663: }
0664: }
0665:
0666: public void pushInteger(int number) {
0667: if (number >= -1 && number <= 5) {
0668: add((byte) (Opcode.ICONST_0 + number));
0669: } else if (number > -0x80 && number < 0x80) {
0670: add(Opcode.BIPUSH, number);
0671: } else if (number > -0x8000 && number < 0x8000) {
0672: add(Opcode.SIPUSH, number);
0673: } else {
0674: add(Opcode.LDC, constantPool.addConstant(number));
0675: }
0676: }
0677:
0678: public void pushLong(long number) {
0679: if (number == 0) {
0680: add(Opcode.LCONST_0);
0681: } else if (number == 1) {
0682: add(Opcode.LCONST_1);
0683: } else {
0684: add(Opcode.LDC2_W, constantPool.addConstant(number));
0685: }
0686: }
0687:
0688: public void pushFloat(float number) {
0689: if (number == 0.0f) {
0690: add(Opcode.FCONST_0);
0691: } else if (number == 1.0f) {
0692: add(Opcode.FCONST_1);
0693: } else if (number == 2.0f) {
0694: add(Opcode.FCONST_2);
0695: } else {
0696: add(Opcode.LDC_W, constantPool.addConstant(number));
0697: }
0698: }
0699:
0700: public void pushDouble(double number) {
0701: if (number == 0) {
0702: add(Opcode.DCONST_0);
0703: } else if (number == 1) {
0704: add(Opcode.DCONST_1);
0705: } else {
0706: add(Opcode.LDC2_W, constantPool.addConstant(number));
0707: }
0708: }
0709:
0710: public void pushString(String str) {
0711: int len = str.length();
0712: if (len > 32767 / 3) {
0713: pushLargeString(str);
0714: } else {
0715: add(Opcode.LDC, addConstant(str));
0716: }
0717: }
0718:
0719: void pushLargeString(String str) {
0720: add(Opcode.NEW, "java.lang.StringBuffer");
0721: add(Opcode.DUP);
0722: add(Opcode.INVOKESPECIAL, "java.lang.StringBuffer", "<init>",
0723: "()", "V");
0724: int x = 32767 / 3;
0725: int len = str.length();
0726: int n = len / x;
0727: int m = len % x;
0728: for (int i = 0; i < n; i++) {
0729: add(Opcode.LDC, addConstant(str.substring(i * x, (i + 1)
0730: * x)));
0731: add(Opcode.INVOKEVIRTUAL, "java.lang.StringBuffer",
0732: "append", "(Ljava/lang/String;)",
0733: "Ljava/lang/StringBuffer;");
0734: }
0735: if (m > 0) {
0736: add(Opcode.LDC, addConstant(str.substring(n * x)));
0737: add(Opcode.INVOKEVIRTUAL, "java.lang.StringBuffer",
0738: "append", "(Ljava/lang/String;)",
0739: "Ljava/lang/StringBuffer;");
0740: }
0741: add(Opcode.INVOKEVIRTUAL, "java.lang.StringBuffer", "toString",
0742: "()", "Ljava/lang/String;");
0743: }
0744:
0745: public void add(byte opcode, int operand) {
0746: updateStack(opcode);
0747: switch (opcode) {
0748: case Opcode.BIPUSH:
0749: codeBuffer.add(opcode);
0750: codeBuffer.add((byte) operand);
0751: break;
0752: case Opcode.SIPUSH:
0753: codeBuffer.add(opcode);
0754: codeBuffer.add((short) operand);
0755: break;
0756: case Opcode.NEWARRAY:
0757: codeBuffer.add(opcode);
0758: codeBuffer.add((byte) operand);
0759: break;
0760: case Opcode.GETFIELD:
0761: case Opcode.PUTFIELD:
0762: codeBuffer.add(opcode);
0763: codeBuffer.add(operand);
0764: break;
0765: case Opcode.LDC:
0766: case Opcode.LDC_W:
0767: case Opcode.LDC2_W:
0768: if ((operand >= 256) || (opcode == Opcode.LDC_W)
0769: || (opcode == Opcode.LDC2_W)) {
0770:
0771: if (opcode == Opcode.LDC) {
0772: codeBuffer.add(Opcode.LDC_W);
0773: } else {
0774: codeBuffer.add(opcode);
0775: }
0776: codeBuffer.add((short) operand);
0777: } else {
0778: codeBuffer.add(opcode);
0779: codeBuffer.add((byte) operand);
0780: }
0781: break;
0782: case Opcode.RET:
0783: case Opcode.ILOAD:
0784: case Opcode.LLOAD:
0785: case Opcode.FLOAD:
0786: case Opcode.DLOAD:
0787: case Opcode.ALOAD:
0788: case Opcode.ISTORE:
0789: case Opcode.LSTORE:
0790: case Opcode.FSTORE:
0791: case Opcode.DSTORE:
0792: case Opcode.ASTORE:
0793: if (operand >= 256) {
0794: codeBuffer.add(Opcode.WIDE);
0795: codeBuffer.add(opcode);
0796: codeBuffer.add((short) operand);
0797: } else {
0798: codeBuffer.add(opcode);
0799: codeBuffer.add((byte) operand);
0800: }
0801: break;
0802: default:
0803: throw new ClassFileException(
0804: "Unexpected opcode for 1 operand");
0805: }
0806: }
0807:
0808: public void add(byte opcode, int operand1, int operand2) {
0809: updateStack(opcode);
0810: if (opcode == Opcode.IINC) {
0811: if ((operand1 > 255) || (operand2 < -128)
0812: || (operand2 > 127)) {
0813: codeBuffer.add(Opcode.WIDE);
0814: codeBuffer.add(Opcode.IINC);
0815: codeBuffer.add((short) operand1);
0816: codeBuffer.add((short) operand2);
0817: } else {
0818: codeBuffer.add(Opcode.IINC);
0819: codeBuffer.add((byte) operand1);
0820: codeBuffer.add((byte) operand2);
0821: }
0822: } else {
0823: if (opcode == Opcode.MULTIANEWARRAY) {
0824: codeBuffer.add(Opcode.MULTIANEWARRAY);
0825: codeBuffer.add((short) operand1);
0826: codeBuffer.add((byte) operand2);
0827: } else {
0828: throw new ClassFileException(
0829: "Unexpected opcode for 2 operands");
0830: }
0831: }
0832: }
0833:
0834: public void add(byte opcode, String className) {
0835: updateStack(opcode);
0836: switch (opcode) {
0837: case Opcode.NEW:
0838: case Opcode.ANEWARRAY:
0839: case Opcode.CHECKCAST:
0840: case Opcode.INSTANCEOF:
0841: short classIndex = constantPool.addClass(className);
0842: codeBuffer.add(opcode);
0843: codeBuffer.add(classIndex);
0844: break;
0845: default:
0846: throw new ClassFileException(
0847: "bad opcode for class reference:" + opcode);
0848: }
0849: }
0850:
0851: public void add(byte opcode, String className, String fieldName,
0852: String fieldType) {
0853: int growth = stackGrowth[opcode & 0xFF];
0854: stackTop += growth;
0855:
0856: char fieldTypeChar = fieldType.charAt(0);
0857: int fieldSize = ((fieldTypeChar == 'J') || (fieldTypeChar == 'D')) ? 2
0858: : 1;
0859:
0860: switch (opcode) {
0861: case Opcode.GETFIELD:
0862: case Opcode.GETSTATIC:
0863: stackTop += fieldSize;
0864: break;
0865: case Opcode.PUTSTATIC:
0866: case Opcode.PUTFIELD:
0867: stackTop -= fieldSize;
0868: break;
0869: default:
0870: throw new ClassFileException(
0871: "bad opcode for field reference:" + opcode);
0872: }
0873: short fieldRefIndex = constantPool.addFieldRef(className,
0874: fieldName, fieldType);
0875: codeBuffer.add(opcode);
0876: codeBuffer.add(fieldRefIndex);
0877:
0878: if (stackTop > maxStack) {
0879: maxStack = stackTop;
0880: }
0881: }
0882:
0883: public void add(byte opcode, String className, String methodName,
0884: String parametersType, String returnType) {
0885: int info = sizeOfParameters(parametersType);
0886: int arg_size = info & 0xffff;
0887:
0888: int growth = stackGrowth[opcode & 0xFF] - arg_size;
0889: stackTop += growth;
0890: /*
0891: * if (stackTop > maxStack){ maxStack = stackTop; }
0892: */
0893: switch (opcode) {
0894: case Opcode.INVOKEVIRTUAL:
0895: case Opcode.INVOKESPECIAL:
0896: case Opcode.INVOKESTATIC:
0897: case Opcode.INVOKEINTERFACE:
0898: stackTop += sizeOfReturn(returnType);
0899: codeBuffer.add(opcode);
0900: if (opcode == Opcode.INVOKEINTERFACE) {
0901: short ifMethodRefIndex = constantPool
0902: .addInterfaceMethodRef(className, methodName,
0903: parametersType + returnType);
0904: codeBuffer.add(ifMethodRefIndex);
0905: codeBuffer.add((byte) (arg_size + 1));
0906: codeBuffer.add((byte) 0);
0907: } else {
0908: short methodRefIndex = constantPool.addMethodRef(
0909: className, methodName, parametersType
0910: + returnType);
0911: codeBuffer.add(methodRefIndex);
0912: }
0913: break;
0914: default:
0915: throw new ClassFileException(
0916: "bad opcode for method reference:" + opcode);
0917: }
0918:
0919: if (stackTop > maxStack) {
0920: maxStack = stackTop;
0921: }
0922: }
0923:
0924: public void reserveStack(int size) {
0925: stackTop += size;
0926: if (stackTop > maxStack) {
0927: maxStack = stackTop;
0928: }
0929: }
0930:
0931: public static final int sizeOfReturn(String sig) {
0932: int size = 0;
0933: char c = sig.charAt(0);
0934: if (c != 'V') {
0935: if ((c == 'J') || (c == 'D')) {
0936: size += 2;
0937: } else {
0938: size++;
0939: }
0940: }
0941: return size;
0942: }
0943:
0944: public static final int sizeOfParameters(String sig) {
0945: return sizeOfParameters(sig.toCharArray(), 1);
0946: }
0947:
0948: static int sizeOfParameters(char c[], int offset) {
0949: int index = offset;
0950: int size = 0;
0951: int narg = 0;
0952: loop: while (index < c.length) {
0953: switch (c[index]) {
0954: case 'J':
0955: case 'D':
0956: size += 2;
0957: index++;
0958: narg++;
0959: break;
0960: case 'B':
0961: case 'S':
0962: case 'C':
0963: case 'I':
0964: case 'Z':
0965: case 'F':
0966: size++;
0967: index++;
0968: narg++;
0969: break;
0970: case '[':
0971: while (c[index] == '[') {
0972: index++;
0973: }
0974: if (c[index] != 'L') {
0975: size++;
0976: index++;
0977: narg++;
0978: break;
0979: } // fall through
0980: case 'L':
0981: size++;
0982: narg++;
0983: while (c[index++] != ';') {
0984: }
0985: break;
0986: case ')':
0987: break loop;
0988: default:
0989: throw new ClassFileException("Bad signature character:"
0990: + c[index]);
0991: }
0992: }
0993: return (narg << 16) | size;
0994: }
0995:
0996: public void addExceptionHandler(Label startLabel, Label endLabel,
0997: Label handlerLabel, String catchClassName) {
0998: short catch_type;
0999: if (catchClassName != null) {
1000: catch_type = constantPool.addClass(catchClassName);
1001: } else {
1002: catch_type = 0;
1003: }
1004: ExceptionTableEntry newEntry = new ExceptionTableEntry(
1005: startLabel, endLabel, handlerLabel, catch_type);
1006:
1007: if (exceptionTable == null) {
1008: exceptionTable = new ArrayList();
1009: }
1010: exceptionTable.add(newEntry);
1011: }
1012:
1013: public void write(OutputStream stream) throws IOException {
1014: DataOutputStream out;
1015: if (stream instanceof DataOutputStream) {
1016: out = (DataOutputStream) stream;
1017: } else {
1018: out = new DataOutputStream(stream);
1019: }
1020: short sourceFileIndex = 0;
1021: if (sourceFileNameIndex != 0) {
1022: sourceFileIndex = constantPool.addUTF8("SourceFile");
1023: }
1024: out.writeLong(MAGIC);
1025: constantPool.write(out);
1026: out.writeShort(this .accessFlags);
1027: out.writeShort(this ClassIndex);
1028: out.writeShort(super ClassIndex);
1029: out.writeShort(interfaces.size());
1030: for (int i = 0; i < interfaces.size(); i++) {
1031: out.writeShort(((Short) interfaces.get(i)).shortValue());
1032: }
1033: out.writeShort(fields.size());
1034: for (int i = 0; i < fields.size(); i++) {
1035: ((FieldInfo) fields.get(i)).write(out);
1036: }
1037: out.writeShort(methods.size());
1038: for (int i = 0; i < methods.size(); i++) {
1039: ((MethodInfo) methods.get(i)).write(out);
1040: }
1041: if (sourceFileNameIndex != 0) {
1042: out.writeShort(1); // attributes count
1043: out.writeShort(sourceFileIndex);
1044: out.writeInt(2);
1045: out.writeShort(sourceFileNameIndex);
1046: } else {
1047: out.writeShort(0); // no attributes
1048: }
1049: }
1050:
1051: public static String signature(Class[] paramTypes) {
1052: StringBuffer buf = new StringBuffer();
1053: buf.append('(');
1054: for (int i = 0; i < paramTypes.length; i++) {
1055: buf.append(signature(paramTypes[i]));
1056: }
1057: buf.append(')');
1058: return buf.toString();
1059: }
1060:
1061: public static String signature(Class clazz) {
1062: if (clazz == int.class) {
1063: return "I";
1064: } else if (clazz == short.class) {
1065: return "S";
1066: } else if (clazz == byte.class) {
1067: return "B";
1068: } else if (clazz == char.class) {
1069: return "C";
1070: } else if (clazz == long.class) {
1071: return "J";
1072: } else if (clazz == float.class) {
1073: return "F";
1074: } else if (clazz == double.class) {
1075: return "D";
1076: } else if (clazz == boolean.class) {
1077: return "Z";
1078: } else if (clazz == void.class) {
1079: return "V";
1080: } else if (clazz.isArray()) {
1081: return "[" + signature(clazz.getComponentType());
1082: } else {
1083: return "L" + clazz.getName().replace('.', '/') + ";";
1084: }
1085: }
1086:
1087: public void addLineNumber(int line) {
1088: LineNumberTable lineNumberTable = this .currentMethod.lineNumberTable;
1089: if (lineNumberTable == null) {
1090: short idx = constantPool.addUTF8("LineNumberTable");
1091: lineNumberTable = new LineNumberTable(idx);
1092: this .currentMethod.lineNumberTable = lineNumberTable;
1093: }
1094: lineNumberTable.addLine(codeSize(), line);
1095: }
1096:
1097: public String toString() {
1098: return getClass().getName() + "[" + className + "]";
1099: }
1100:
1101: static class ExceptionAttr {
1102: private short nameIndex;
1103:
1104: private short[] exceptionIndex;
1105:
1106: ExceptionAttr(short nameIndex, short[] exceptionIndex) {
1107: this .nameIndex = nameIndex;
1108: this .exceptionIndex = exceptionIndex;
1109: }
1110:
1111: void write(DataOutputStream out) throws IOException {
1112: out.writeShort(nameIndex);
1113: int n = exceptionIndex.length;
1114: out.writeInt(n * 2 + 2);
1115: out.writeShort(n);
1116: for (int i = 0; i < n; i++) {
1117: out.writeShort(exceptionIndex[i]);
1118: }
1119: }
1120: }
1121:
1122: static class MethodInfo {
1123:
1124: short nameIndex;
1125:
1126: short descriptorIndex;
1127:
1128: short accessFlags;
1129:
1130: ExceptionAttr exceptions;
1131:
1132: ByteBuffer codeAttribute;
1133:
1134: LineNumberTable lineNumberTable;
1135:
1136: MethodInfo(short nameIndex, short descriptorIndex,
1137: short accessFlags, ExceptionAttr exceptions) {
1138: this .nameIndex = nameIndex;
1139: this .descriptorIndex = descriptorIndex;
1140: this .accessFlags = accessFlags;
1141: this .exceptions = exceptions;
1142: }
1143:
1144: ByteBuffer getCodeAttribute() {
1145: return this .codeAttribute;
1146: }
1147:
1148: void setCodeAttribute(ByteBuffer codeAttribute) {
1149: this .codeAttribute = codeAttribute;
1150: }
1151:
1152: void write(DataOutputStream out) throws IOException {
1153: out.writeShort(accessFlags);
1154: out.writeShort(nameIndex);
1155: out.writeShort(descriptorIndex);
1156: int count = 0;
1157: if (codeAttribute != null) {
1158: count++;
1159: }
1160: if (exceptions != null) {
1161: count++;
1162: }
1163: out.writeShort(count);
1164: if (exceptions != null) {
1165: exceptions.write(out);
1166: }
1167: if (codeAttribute != null) {
1168: codeAttribute.writeTo(out);
1169: }
1170: if (lineNumberTable != null) {
1171: lineNumberTable.write(out);
1172: }
1173: }
1174: }
1175:
1176: static class FieldInfo {
1177:
1178: private short nameIndex;
1179:
1180: private short descriptorIndex;
1181:
1182: private short accessFlags;
1183:
1184: private short attributes[];
1185:
1186: FieldInfo(short nameIndex, short descriptorIndex,
1187: short accessFlags) {
1188: this .nameIndex = nameIndex;
1189: this .descriptorIndex = descriptorIndex;
1190: this .accessFlags = accessFlags;
1191: }
1192:
1193: FieldInfo(short nameIndex, short descriptorIndex,
1194: short accessFlags, short attributes[]) {
1195: this .nameIndex = nameIndex;
1196: this .descriptorIndex = descriptorIndex;
1197: this .accessFlags = accessFlags;
1198: this .attributes = attributes;
1199: }
1200:
1201: void write(DataOutputStream out) throws IOException {
1202: out.writeShort(accessFlags);
1203: out.writeShort(nameIndex);
1204: out.writeShort(descriptorIndex);
1205: if (attributes == null) {
1206: out.writeShort(0); // no attributes
1207: } else {
1208: out.writeShort(1);
1209: out.writeShort(attributes[0]);
1210: out.writeShort(attributes[1]);
1211: out.writeShort(attributes[2]);
1212: out.writeShort(attributes[3]);
1213: }
1214: }
1215: }
1216:
1217: static class ExceptionTableEntry {
1218:
1219: Label start;
1220:
1221: Label end;
1222:
1223: Label handler;
1224:
1225: short catchType;
1226:
1227: ExceptionTableEntry(Label start, Label end, Label handler,
1228: short catchType) {
1229: this .start = start;
1230: this .end = end;
1231: this .handler = handler;
1232: this .catchType = catchType;
1233: }
1234: }
1235:
1236: static class LineNumberTable {
1237: IntArray pcArray;
1238: IntArray lineArray;
1239: short idx;
1240:
1241: LineNumberTable(short attributeNameIndex) {
1242: this .pcArray = new IntArray();
1243: this .lineArray = new IntArray();
1244: this .idx = attributeNameIndex;
1245: }
1246:
1247: public void addLine(int pc, int line) {
1248: pcArray.add(pc);
1249: lineArray.add(line);
1250: }
1251:
1252: public int size() {
1253: return pcArray.size();
1254: }
1255:
1256: public void shift(int offset) {
1257: int size = pcArray.size();
1258: int[] pa = pcArray.getArray();
1259: for (int i = 0; i < size; i++) {
1260: pa[i] += offset;
1261: }
1262: }
1263:
1264: void write(DataOutputStream out) throws IOException {
1265: out.writeShort(idx);
1266: int size = pcArray.size();
1267: out.writeInt(2 + 4 * size);
1268: out.writeShort((short) size);
1269: int[] pa = pcArray.getArray();
1270: int[] la = lineArray.getArray();
1271: for (int i = 0; i < size; i++) {
1272: out.writeShort((short) pa[i]);
1273: out.writeShort((short) la[i]);
1274: }
1275: }
1276: }
1277: }
|