0001: /*
0002: * Javassist, a Java-bytecode translator toolkit.
0003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
0004: *
0005: * The contents of this file are subject to the Mozilla Public License Version
0006: * 1.1 (the "License"); you may not use this file except in compliance with
0007: * the License. Alternatively, the contents of this file may be used under
0008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
0009: *
0010: * Software distributed under the License is distributed on an "AS IS" basis,
0011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012: * for the specific language governing rights and limitations under the
0013: * License.
0014: */
0015:
0016: package javassist.bytecode;
0017:
0018: import javassist.CtClass;
0019: import javassist.CtPrimitiveType;
0020:
0021: class ByteVector implements Cloneable {
0022: private byte[] buffer;
0023: private int size;
0024:
0025: public ByteVector() {
0026: buffer = new byte[64];
0027: size = 0;
0028: }
0029:
0030: public Object clone() throws CloneNotSupportedException {
0031: ByteVector bv = (ByteVector) super .clone();
0032: bv.buffer = (byte[]) buffer.clone();
0033: return bv;
0034: }
0035:
0036: public final int getSize() {
0037: return size;
0038: }
0039:
0040: public final byte[] copy() {
0041: byte[] b = new byte[size];
0042: arraycopy(buffer, b, size);
0043: return b;
0044: }
0045:
0046: public int read(int offset) {
0047: if (offset < 0 || size <= offset)
0048: throw new ArrayIndexOutOfBoundsException(offset);
0049:
0050: return buffer[offset];
0051: }
0052:
0053: public void write(int offset, int value) {
0054: if (offset < 0 || size <= offset)
0055: throw new ArrayIndexOutOfBoundsException(offset);
0056:
0057: buffer[offset] = (byte) value;
0058: }
0059:
0060: public void add(int code) {
0061: addGap(1);
0062: buffer[size - 1] = (byte) code;
0063: }
0064:
0065: public void addGap(int length) {
0066: if (size + length > buffer.length) {
0067: int newSize = size << 1;
0068: if (newSize < size + length)
0069: newSize = size + length;
0070:
0071: byte[] newBuf = new byte[newSize];
0072: arraycopy(buffer, newBuf, size);
0073: buffer = newBuf;
0074: }
0075:
0076: size += length;
0077: }
0078:
0079: private static void arraycopy(byte[] src, byte[] dest, int size) {
0080: for (int i = 0; i < size; i++)
0081: dest[i] = src[i];
0082: }
0083: }
0084:
0085: /**
0086: * A utility class for producing a bytecode sequence.
0087: *
0088: * <p>A <code>Bytecode</code> object is an unbounded array
0089: * containing bytecode. For example,
0090: *
0091: * <ul><pre>ConstPool cp = ...; // constant pool table
0092: * Bytecode b = new Bytecode(cp, 1, 0);
0093: * b.addIconst(3);
0094: * b.addReturn(CtClass.intType);
0095: * CodeAttribute ca = b.toCodeAttribute();</ul></pre>
0096: *
0097: * <p>This program produces a Code attribute including a bytecode
0098: * sequence:
0099: *
0100: * <ul><pre>iconst_3
0101: * ireturn</pre></ul>
0102: *
0103: * @see ConstPool
0104: * @see CodeAttribute
0105: */
0106: public class Bytecode extends ByteVector implements Cloneable, Opcode {
0107: /**
0108: * Represents the <code>CtClass</code> file using the
0109: * constant pool table given to this <code>Bytecode</code> object.
0110: */
0111: public static final CtClass THIS = ConstPool.THIS;
0112:
0113: ConstPool constPool;
0114: int maxStack, maxLocals;
0115: ExceptionTable tryblocks;
0116: private int stackDepth;
0117:
0118: /**
0119: * Constructs a <code>Bytecode</code> object with an empty bytecode
0120: * sequence.
0121: *
0122: * <p>The parameters <code>stacksize</code> and <code>localvars</code>
0123: * specify initial values
0124: * of <code>max_stack</code> and <code>max_locals</code>.
0125: * They can be changed later.
0126: *
0127: * @param cp constant pool table.
0128: * @param stacksize <code>max_stack</code>.
0129: * @param localvars <code>max_locals</code>.
0130: */
0131: public Bytecode(ConstPool cp, int stacksize, int localvars) {
0132: constPool = cp;
0133: maxStack = stacksize;
0134: maxLocals = localvars;
0135: tryblocks = new ExceptionTable(cp);
0136: stackDepth = 0;
0137: }
0138:
0139: /**
0140: * Constructs a <code>Bytecode</code> object with an empty bytecode
0141: * sequence. The initial values of <code>max_stack</code> and
0142: * <code>max_locals</code> are zero.
0143: *
0144: * @param cp constant pool table.
0145: * @see Bytecode#setMaxStack(int)
0146: * @see Bytecode#setMaxLocals(int)
0147: */
0148: public Bytecode(ConstPool cp) {
0149: this (cp, 0, 0);
0150: }
0151:
0152: /**
0153: * Creates and returns a copy of this object.
0154: * The constant pool object is shared between this object
0155: * and the cloned object.
0156: */
0157: public Object clone() {
0158: try {
0159: Bytecode bc = (Bytecode) super .clone();
0160: bc.tryblocks = (ExceptionTable) tryblocks.clone();
0161: return bc;
0162: } catch (CloneNotSupportedException cnse) {
0163: throw new RuntimeException(cnse);
0164: }
0165: }
0166:
0167: /**
0168: * Gets a constant pool table.
0169: */
0170: public ConstPool getConstPool() {
0171: return constPool;
0172: }
0173:
0174: /**
0175: * Returns <code>exception_table</code>.
0176: */
0177: public ExceptionTable getExceptionTable() {
0178: return tryblocks;
0179: }
0180:
0181: /**
0182: * Converts to a <code>CodeAttribute</code>.
0183: */
0184: public CodeAttribute toCodeAttribute() {
0185: return new CodeAttribute(constPool, maxStack, maxLocals, get(),
0186: tryblocks);
0187: }
0188:
0189: /**
0190: * Returns the length of the bytecode sequence.
0191: */
0192: public int length() {
0193: return getSize();
0194: }
0195:
0196: /**
0197: * Returns the produced bytecode sequence.
0198: */
0199: public byte[] get() {
0200: return copy();
0201: }
0202:
0203: /**
0204: * Gets <code>max_stack</code>.
0205: */
0206: public int getMaxStack() {
0207: return maxStack;
0208: }
0209:
0210: /**
0211: * Sets <code>max_stack</code>.
0212: *
0213: * <p>This value may be automatically updated when an instruction
0214: * is appended. A <code>Bytecode</code> object maintains the current
0215: * stack depth whenever an instruction is added
0216: * by <code>addOpcode()</code>. For example, if DUP is appended,
0217: * the current stack depth is increased by one. If the new stack
0218: * depth is more than <code>max_stack</code>, then it is assigned
0219: * to <code>max_stack</code>. However, if branch instructions are
0220: * appended, the current stack depth may not be correctly maintained.
0221: *
0222: * @see #addOpcode(int)
0223: */
0224: public void setMaxStack(int size) {
0225: maxStack = size;
0226: }
0227:
0228: /**
0229: * Gets <code>max_locals</code>.
0230: */
0231: public int getMaxLocals() {
0232: return maxLocals;
0233: }
0234:
0235: /**
0236: * Sets <code>max_locals</code>.
0237: */
0238: public void setMaxLocals(int size) {
0239: maxLocals = size;
0240: }
0241:
0242: /**
0243: * Sets <code>max_locals</code>.
0244: *
0245: * <p>This computes the number of local variables
0246: * used to pass method parameters and sets <code>max_locals</code>
0247: * to that number plus <code>locals</code>.
0248: *
0249: * @param isStatic true if <code>params</code> must be
0250: * interpreted as parameters to a static method.
0251: * @param params parameter types.
0252: * @param locals the number of local variables excluding
0253: * ones used to pass parameters.
0254: */
0255: public void setMaxLocals(boolean isStatic, CtClass[] params,
0256: int locals) {
0257: if (!isStatic)
0258: ++locals;
0259:
0260: if (params != null) {
0261: CtClass doubleType = CtClass.doubleType;
0262: CtClass longType = CtClass.longType;
0263: int n = params.length;
0264: for (int i = 0; i < n; ++i) {
0265: CtClass type = params[i];
0266: if (type == doubleType || type == longType)
0267: locals += 2;
0268: else
0269: ++locals;
0270: }
0271: }
0272:
0273: maxLocals = locals;
0274: }
0275:
0276: /**
0277: * Increments <code>max_locals</code>.
0278: */
0279: public void incMaxLocals(int diff) {
0280: maxLocals += diff;
0281: }
0282:
0283: /**
0284: * Adds a new entry of <code>exception_table</code>.
0285: */
0286: public void addExceptionHandler(int start, int end, int handler,
0287: CtClass type) {
0288: addExceptionHandler(start, end, handler, constPool
0289: .addClassInfo(type));
0290: }
0291:
0292: /**
0293: * Adds a new entry of <code>exception_table</code>.
0294: *
0295: * @param type the fully-qualified name of a throwable class.
0296: */
0297: public void addExceptionHandler(int start, int end, int handler,
0298: String type) {
0299: addExceptionHandler(start, end, handler, constPool
0300: .addClassInfo(type));
0301: }
0302:
0303: /**
0304: * Adds a new entry of <code>exception_table</code>.
0305: */
0306: public void addExceptionHandler(int start, int end, int handler,
0307: int type) {
0308: tryblocks.add(start, end, handler, type);
0309: }
0310:
0311: /**
0312: * Returns the length of bytecode sequence
0313: * that have been added so far.
0314: */
0315: public int currentPc() {
0316: return getSize();
0317: }
0318:
0319: /**
0320: * Reads a signed 8bit value at the offset from the beginning of the
0321: * bytecode sequence.
0322: *
0323: * @throws ArrayIndexOutOfBoundsException if offset is invalid.
0324: */
0325: public int read(int offset) {
0326: return super .read(offset);
0327: }
0328:
0329: /**
0330: * Reads a signed 16bit value at the offset from the beginning of the
0331: * bytecode sequence.
0332: */
0333: public int read16bit(int offset) {
0334: int v1 = read(offset);
0335: int v2 = read(offset + 1);
0336: return (v1 << 8) + (v2 & 0xff);
0337: }
0338:
0339: /**
0340: * Reads a signed 32bit value at the offset from the beginning of the
0341: * bytecode sequence.
0342: */
0343: public int read32bit(int offset) {
0344: int v1 = read16bit(offset);
0345: int v2 = read16bit(offset + 2);
0346: return (v1 << 16) + (v2 & 0xffff);
0347: }
0348:
0349: /**
0350: * Writes an 8bit value at the offset from the beginning of the
0351: * bytecode sequence.
0352: *
0353: * @throws ArrayIndexOutOfBoundsException if offset is invalid.
0354: */
0355: public void write(int offset, int value) {
0356: super .write(offset, value);
0357: }
0358:
0359: /**
0360: * Writes an 16bit value at the offset from the beginning of the
0361: * bytecode sequence.
0362: */
0363: public void write16bit(int offset, int value) {
0364: write(offset, value >> 8);
0365: write(offset + 1, value);
0366: }
0367:
0368: /**
0369: * Writes an 32bit value at the offset from the beginning of the
0370: * bytecode sequence.
0371: */
0372: public void write32bit(int offset, int value) {
0373: write16bit(offset, value >> 16);
0374: write16bit(offset + 2, value);
0375: }
0376:
0377: /**
0378: * Appends an 8bit value to the end of the bytecode sequence.
0379: */
0380: public void add(int code) {
0381: super .add(code);
0382: }
0383:
0384: /**
0385: * Appends a 32bit value to the end of the bytecode sequence.
0386: */
0387: public void add32bit(int value) {
0388: add(value >> 24);
0389: add(value >> 16);
0390: add(value >> 8);
0391: add(value);
0392: }
0393:
0394: /**
0395: * Appends the length-byte gap to the end of the bytecode sequence.
0396: *
0397: * @param length the gap length in byte.
0398: */
0399: public void addGap(int length) {
0400: super .addGap(length);
0401: }
0402:
0403: /**
0404: * Appends an 8bit opcode to the end of the bytecode sequence.
0405: * The current stack depth is updated.
0406: * <code>max_stack</code> is updated if the current stack depth
0407: * is the deepest so far.
0408: *
0409: * <p>Note: some instructions such as INVOKEVIRTUAL does not
0410: * update the current stack depth since the increment depends
0411: * on the method signature.
0412: * <code>growStack()</code> must be explicitly called.
0413: */
0414: public void addOpcode(int code) {
0415: add(code);
0416: growStack(STACK_GROW[code]);
0417: }
0418:
0419: /**
0420: * Increases the current stack depth.
0421: * It also updates <code>max_stack</code> if the current stack depth
0422: * is the deepest so far.
0423: *
0424: * @param diff the number added to the current stack depth.
0425: */
0426: public void growStack(int diff) {
0427: setStackDepth(stackDepth + diff);
0428: }
0429:
0430: /**
0431: * Returns the current stack depth.
0432: */
0433: public int getStackDepth() {
0434: return stackDepth;
0435: }
0436:
0437: /**
0438: * Sets the current stack depth.
0439: * It also updates <code>max_stack</code> if the current stack depth
0440: * is the deepest so far.
0441: *
0442: * @param depth new value.
0443: */
0444: public void setStackDepth(int depth) {
0445: stackDepth = depth;
0446: if (stackDepth > maxStack)
0447: maxStack = stackDepth;
0448: }
0449:
0450: /**
0451: * Appends a 16bit value to the end of the bytecode sequence.
0452: * It never changes the current stack depth.
0453: */
0454: public void addIndex(int index) {
0455: add(index >> 8);
0456: add(index);
0457: }
0458:
0459: /**
0460: * Appends ALOAD or (WIDE) ALOAD_<n>
0461: *
0462: * @param n an index into the local variable array.
0463: */
0464: public void addAload(int n) {
0465: if (n < 4)
0466: addOpcode(42 + n); // aload_<n>
0467: else if (n < 0x100) {
0468: addOpcode(ALOAD); // aload
0469: add(n);
0470: } else {
0471: addOpcode(WIDE);
0472: addOpcode(ALOAD);
0473: addIndex(n);
0474: }
0475: }
0476:
0477: /**
0478: * Appends ASTORE or (WIDE) ASTORE_<n>
0479: *
0480: * @param n an index into the local variable array.
0481: */
0482: public void addAstore(int n) {
0483: if (n < 4)
0484: addOpcode(75 + n); // astore_<n>
0485: else if (n < 0x100) {
0486: addOpcode(ASTORE); // astore
0487: add(n);
0488: } else {
0489: addOpcode(WIDE);
0490: addOpcode(ASTORE);
0491: addIndex(n);
0492: }
0493: }
0494:
0495: /**
0496: * Appends ICONST or ICONST_<n>
0497: *
0498: * @param n the pushed integer constant.
0499: */
0500: public void addIconst(int n) {
0501: if (n < 6 && -2 < n)
0502: addOpcode(3 + n); // iconst_<i> -1..5
0503: else if (n <= 127 && -128 <= n) {
0504: addOpcode(16); // bipush
0505: add(n);
0506: } else if (n <= 32767 && -32768 <= n) {
0507: addOpcode(17); // sipush
0508: add(n >> 8);
0509: add(n);
0510: } else
0511: addLdc(constPool.addIntegerInfo(n));
0512: }
0513:
0514: /**
0515: * Appends an instruction for pushing zero or null on the stack.
0516: * If the type is void, this method does not append any instruction.
0517: *
0518: * @param type the type of the zero value (or null).
0519: */
0520: public void addConstZero(CtClass type) {
0521: if (type.isPrimitive()) {
0522: if (type == CtClass.longType)
0523: addOpcode(LCONST_0);
0524: else if (type == CtClass.floatType)
0525: addOpcode(FCONST_0);
0526: else if (type == CtClass.doubleType)
0527: addOpcode(DCONST_0);
0528: else if (type == CtClass.voidType)
0529: throw new RuntimeException("void type?");
0530: else
0531: addOpcode(ICONST_0);
0532: } else
0533: addOpcode(ACONST_NULL);
0534: }
0535:
0536: /**
0537: * Appends ILOAD or (WIDE) ILOAD_<n>
0538: *
0539: * @param n an index into the local variable array.
0540: */
0541: public void addIload(int n) {
0542: if (n < 4)
0543: addOpcode(26 + n); // iload_<n>
0544: else if (n < 0x100) {
0545: addOpcode(ILOAD); // iload
0546: add(n);
0547: } else {
0548: addOpcode(WIDE);
0549: addOpcode(ILOAD);
0550: addIndex(n);
0551: }
0552: }
0553:
0554: /**
0555: * Appends ISTORE or (WIDE) ISTORE_<n>
0556: *
0557: * @param n an index into the local variable array.
0558: */
0559: public void addIstore(int n) {
0560: if (n < 4)
0561: addOpcode(59 + n); // istore_<n>
0562: else if (n < 0x100) {
0563: addOpcode(ISTORE); // istore
0564: add(n);
0565: } else {
0566: addOpcode(WIDE);
0567: addOpcode(ISTORE);
0568: addIndex(n);
0569: }
0570: }
0571:
0572: /**
0573: * Appends LCONST or LCONST_<n>
0574: *
0575: * @param n the pushed long integer constant.
0576: */
0577: public void addLconst(long n) {
0578: if (n == 0 || n == 1)
0579: addOpcode(9 + (int) n); // lconst_<n>
0580: else
0581: addLdc2w(n);
0582: }
0583:
0584: /**
0585: * Appends LLOAD or (WIDE) LLOAD_<n>
0586: *
0587: * @param n an index into the local variable array.
0588: */
0589: public void addLload(int n) {
0590: if (n < 4)
0591: addOpcode(30 + n); // lload_<n>
0592: else if (n < 0x100) {
0593: addOpcode(LLOAD); // lload
0594: add(n);
0595: } else {
0596: addOpcode(WIDE);
0597: addOpcode(LLOAD);
0598: addIndex(n);
0599: }
0600: }
0601:
0602: /**
0603: * Appends LSTORE or LSTORE_<n>
0604: *
0605: * @param n an index into the local variable array.
0606: */
0607: public void addLstore(int n) {
0608: if (n < 4)
0609: addOpcode(63 + n); // lstore_<n>
0610: else if (n < 0x100) {
0611: addOpcode(LSTORE); // lstore
0612: add(n);
0613: } else {
0614: addOpcode(WIDE);
0615: addOpcode(LSTORE);
0616: addIndex(n);
0617: }
0618: }
0619:
0620: /**
0621: * Appends DCONST or DCONST_<n>
0622: *
0623: * @param d the pushed double constant.
0624: */
0625: public void addDconst(double d) {
0626: if (d == 0.0 || d == 1.0)
0627: addOpcode(14 + (int) d); // dconst_<n>
0628: else
0629: addLdc2w(d);
0630: }
0631:
0632: /**
0633: * Appends DLOAD or (WIDE) DLOAD_<n>
0634: *
0635: * @param n an index into the local variable array.
0636: */
0637: public void addDload(int n) {
0638: if (n < 4)
0639: addOpcode(38 + n); // dload_<n>
0640: else if (n < 0x100) {
0641: addOpcode(DLOAD); // dload
0642: add(n);
0643: } else {
0644: addOpcode(WIDE);
0645: addOpcode(DLOAD);
0646: addIndex(n);
0647: }
0648: }
0649:
0650: /**
0651: * Appends DSTORE or (WIDE) DSTORE_<n>
0652: *
0653: * @param n an index into the local variable array.
0654: */
0655: public void addDstore(int n) {
0656: if (n < 4)
0657: addOpcode(71 + n); // dstore_<n>
0658: else if (n < 0x100) {
0659: addOpcode(DSTORE); // dstore
0660: add(n);
0661: } else {
0662: addOpcode(WIDE);
0663: addOpcode(DSTORE);
0664: addIndex(n);
0665: }
0666: }
0667:
0668: /**
0669: * Appends FCONST or FCONST_<n>
0670: *
0671: * @param f the pushed float constant.
0672: */
0673: public void addFconst(float f) {
0674: if (f == 0.0f || f == 1.0f || f == 2.0f)
0675: addOpcode(11 + (int) f); // fconst_<n>
0676: else
0677: addLdc(constPool.addFloatInfo(f));
0678: }
0679:
0680: /**
0681: * Appends FLOAD or (WIDE) FLOAD_<n>
0682: *
0683: * @param n an index into the local variable array.
0684: */
0685: public void addFload(int n) {
0686: if (n < 4)
0687: addOpcode(34 + n); // fload_<n>
0688: else if (n < 0x100) {
0689: addOpcode(FLOAD); // fload
0690: add(n);
0691: } else {
0692: addOpcode(WIDE);
0693: addOpcode(FLOAD);
0694: addIndex(n);
0695: }
0696: }
0697:
0698: /**
0699: * Appends FSTORE or FSTORE_<n>
0700: *
0701: * @param n an index into the local variable array.
0702: */
0703: public void addFstore(int n) {
0704: if (n < 4)
0705: addOpcode(67 + n); // fstore_<n>
0706: else if (n < 0x100) {
0707: addOpcode(FSTORE); // fstore
0708: add(n);
0709: } else {
0710: addOpcode(WIDE);
0711: addOpcode(FSTORE);
0712: addIndex(n);
0713: }
0714: }
0715:
0716: /**
0717: * Appends an instruction for loading a value from the
0718: * local variable at the index <code>n</code>.
0719: *
0720: * @param n the index.
0721: * @param type the type of the loaded value.
0722: * @return the size of the value (1 or 2 word).
0723: */
0724: public int addLoad(int n, CtClass type) {
0725: if (type.isPrimitive()) {
0726: if (type == CtClass.booleanType || type == CtClass.charType
0727: || type == CtClass.byteType
0728: || type == CtClass.shortType
0729: || type == CtClass.intType)
0730: addIload(n);
0731: else if (type == CtClass.longType) {
0732: addLload(n);
0733: return 2;
0734: } else if (type == CtClass.floatType)
0735: addFload(n);
0736: else if (type == CtClass.doubleType) {
0737: addDload(n);
0738: return 2;
0739: } else
0740: throw new RuntimeException("void type?");
0741: } else
0742: addAload(n);
0743:
0744: return 1;
0745: }
0746:
0747: /**
0748: * Appends an instruction for storing a value into the
0749: * local variable at the index <code>n</code>.
0750: *
0751: * @param n the index.
0752: * @param type the type of the stored value.
0753: * @return 2 if the type is long or double. Otherwise 1.
0754: */
0755: public int addStore(int n, CtClass type) {
0756: if (type.isPrimitive()) {
0757: if (type == CtClass.booleanType || type == CtClass.charType
0758: || type == CtClass.byteType
0759: || type == CtClass.shortType
0760: || type == CtClass.intType)
0761: addIstore(n);
0762: else if (type == CtClass.longType) {
0763: addLstore(n);
0764: return 2;
0765: } else if (type == CtClass.floatType)
0766: addFstore(n);
0767: else if (type == CtClass.doubleType) {
0768: addDstore(n);
0769: return 2;
0770: } else
0771: throw new RuntimeException("void type?");
0772: } else
0773: addAstore(n);
0774:
0775: return 1;
0776: }
0777:
0778: /**
0779: * Appends instructions for loading all the parameters onto the
0780: * operand stack.
0781: *
0782: * @param offset the index of the first parameter. It is 0
0783: * if the method is static. Otherwise, it is 1.
0784: */
0785: public int addLoadParameters(CtClass[] params, int offset) {
0786: int stacksize = 0;
0787: if (params != null) {
0788: int n = params.length;
0789: for (int i = 0; i < n; ++i)
0790: stacksize += addLoad(stacksize + offset, params[i]);
0791: }
0792:
0793: return stacksize;
0794: }
0795:
0796: /**
0797: * Appends CHECKCAST.
0798: *
0799: * @param c the type.
0800: */
0801: public void addCheckcast(CtClass c) {
0802: addOpcode(CHECKCAST);
0803: addIndex(constPool.addClassInfo(c));
0804: }
0805:
0806: /**
0807: * Appends CHECKCAST.
0808: *
0809: * @param classname a fully-qualified class name.
0810: */
0811: public void addCheckcast(String classname) {
0812: addOpcode(CHECKCAST);
0813: addIndex(constPool.addClassInfo(classname));
0814: }
0815:
0816: /**
0817: * Appends INSTANCEOF.
0818: *
0819: * @param classname the class name.
0820: */
0821: public void addInstanceof(String classname) {
0822: addOpcode(INSTANCEOF);
0823: addIndex(constPool.addClassInfo(classname));
0824: }
0825:
0826: /**
0827: * Appends GETFIELD.
0828: *
0829: * @param c the class.
0830: * @param name the field name.
0831: * @param type the descriptor of the field type.
0832: *
0833: * @see Descriptor#of(CtClass)
0834: */
0835: public void addGetfield(CtClass c, String name, String type) {
0836: add(GETFIELD);
0837: int ci = constPool.addClassInfo(c);
0838: addIndex(constPool.addFieldrefInfo(ci, name, type));
0839: growStack(Descriptor.dataSize(type) - 1);
0840: }
0841:
0842: /**
0843: * Appends GETFIELD.
0844: *
0845: * @param c the fully-qualified class name.
0846: * @param name the field name.
0847: * @param type the descriptor of the field type.
0848: *
0849: * @see Descriptor#of(CtClass)
0850: */
0851: public void addGetfield(String c, String name, String type) {
0852: add(GETFIELD);
0853: int ci = constPool.addClassInfo(c);
0854: addIndex(constPool.addFieldrefInfo(ci, name, type));
0855: growStack(Descriptor.dataSize(type) - 1);
0856: }
0857:
0858: /**
0859: * Appends GETSTATIC.
0860: *
0861: * @param c the class
0862: * @param name the field name
0863: * @param type the descriptor of the field type.
0864: *
0865: * @see Descriptor#of(CtClass)
0866: */
0867: public void addGetstatic(CtClass c, String name, String type) {
0868: add(GETSTATIC);
0869: int ci = constPool.addClassInfo(c);
0870: addIndex(constPool.addFieldrefInfo(ci, name, type));
0871: growStack(Descriptor.dataSize(type));
0872: }
0873:
0874: /**
0875: * Appends GETSTATIC.
0876: *
0877: * @param c the fully-qualified class name
0878: * @param name the field name
0879: * @param type the descriptor of the field type.
0880: *
0881: * @see Descriptor#of(CtClass)
0882: */
0883: public void addGetstatic(String c, String name, String type) {
0884: add(GETSTATIC);
0885: int ci = constPool.addClassInfo(c);
0886: addIndex(constPool.addFieldrefInfo(ci, name, type));
0887: growStack(Descriptor.dataSize(type));
0888: }
0889:
0890: /**
0891: * Appends INVOKESPECIAL.
0892: *
0893: * @param clazz the target class.
0894: * @param name the method name.
0895: * @param returnType the return type.
0896: * @param paramTypes the parameter types.
0897: */
0898: public void addInvokespecial(CtClass clazz, String name,
0899: CtClass returnType, CtClass[] paramTypes) {
0900: String desc = Descriptor.ofMethod(returnType, paramTypes);
0901: addInvokespecial(clazz, name, desc);
0902: }
0903:
0904: /**
0905: * Appends INVOKESPECIAL.
0906: *
0907: * @param clazz the target class.
0908: * @param name the method name
0909: * @param desc the descriptor of the method signature.
0910: *
0911: * @see Descriptor#ofMethod(CtClass,CtClass[])
0912: * @see Descriptor#ofConstructor(CtClass[])
0913: */
0914: public void addInvokespecial(CtClass clazz, String name, String desc) {
0915: addInvokespecial(constPool.addClassInfo(clazz), name, desc);
0916: }
0917:
0918: /**
0919: * Appends INVOKESPECIAL.
0920: *
0921: * @param clazz the fully-qualified class name.
0922: * @param name the method name
0923: * @param desc the descriptor of the method signature.
0924: *
0925: * @see Descriptor#ofMethod(CtClass,CtClass[])
0926: * @see Descriptor#ofConstructor(CtClass[])
0927: */
0928: public void addInvokespecial(String clazz, String name, String desc) {
0929: addInvokespecial(constPool.addClassInfo(clazz), name, desc);
0930: }
0931:
0932: /**
0933: * Appends INVOKESPECIAL.
0934: *
0935: * @param clazz the index of <code>CONSTANT_Class_info</code>
0936: * structure.
0937: * @param name the method name
0938: * @param desc the descriptor of the method signature.
0939: *
0940: * @see Descriptor#ofMethod(CtClass,CtClass[])
0941: * @see Descriptor#ofConstructor(CtClass[])
0942: */
0943: public void addInvokespecial(int clazz, String name, String desc) {
0944: add(INVOKESPECIAL);
0945: addIndex(constPool.addMethodrefInfo(clazz, name, desc));
0946: growStack(Descriptor.dataSize(desc) - 1);
0947: }
0948:
0949: /**
0950: * Appends INVOKESTATIC.
0951: *
0952: * @param clazz the target class.
0953: * @param name the method name
0954: * @param returnType the return type.
0955: * @param paramTypes the parameter types.
0956: */
0957: public void addInvokestatic(CtClass clazz, String name,
0958: CtClass returnType, CtClass[] paramTypes) {
0959: String desc = Descriptor.ofMethod(returnType, paramTypes);
0960: addInvokestatic(clazz, name, desc);
0961: }
0962:
0963: /**
0964: * Appends INVOKESTATIC.
0965: *
0966: * @param clazz the target class.
0967: * @param name the method name
0968: * @param desc the descriptor of the method signature.
0969: *
0970: * @see Descriptor#ofMethod(CtClass,CtClass[])
0971: */
0972: public void addInvokestatic(CtClass clazz, String name, String desc) {
0973: addInvokestatic(constPool.addClassInfo(clazz), name, desc);
0974: }
0975:
0976: /**
0977: * Appends INVOKESTATIC.
0978: *
0979: * @param classname the fully-qualified class name.
0980: * @param name the method name
0981: * @param desc the descriptor of the method signature.
0982: *
0983: * @see Descriptor#ofMethod(CtClass,CtClass[])
0984: */
0985: public void addInvokestatic(String classname, String name,
0986: String desc) {
0987: addInvokestatic(constPool.addClassInfo(classname), name, desc);
0988: }
0989:
0990: /**
0991: * Appends INVOKESTATIC.
0992: *
0993: * @param clazz the index of <code>CONSTANT_Class_info</code>
0994: * structure.
0995: * @param name the method name
0996: * @param desc the descriptor of the method signature.
0997: *
0998: * @see Descriptor#ofMethod(CtClass,CtClass[])
0999: */
1000: public void addInvokestatic(int clazz, String name, String desc) {
1001: add(INVOKESTATIC);
1002: addIndex(constPool.addMethodrefInfo(clazz, name, desc));
1003: growStack(Descriptor.dataSize(desc));
1004: }
1005:
1006: /**
1007: * Appends INVOKEVIRTUAL.
1008: *
1009: * <p>The specified method must not be an inherited method.
1010: * It must be directly declared in the class specified
1011: * in <code>clazz</code>.
1012: *
1013: * @param clazz the target class.
1014: * @param name the method name
1015: * @param returnType the return type.
1016: * @param paramTypes the parameter types.
1017: */
1018: public void addInvokevirtual(CtClass clazz, String name,
1019: CtClass returnType, CtClass[] paramTypes) {
1020: String desc = Descriptor.ofMethod(returnType, paramTypes);
1021: addInvokevirtual(clazz, name, desc);
1022: }
1023:
1024: /**
1025: * Appends INVOKEVIRTUAL.
1026: *
1027: * <p>The specified method must not be an inherited method.
1028: * It must be directly declared in the class specified
1029: * in <code>clazz</code>.
1030: *
1031: * @param clazz the target class.
1032: * @param name the method name
1033: * @param desc the descriptor of the method signature.
1034: *
1035: * @see Descriptor#ofMethod(CtClass,CtClass[])
1036: */
1037: public void addInvokevirtual(CtClass clazz, String name, String desc) {
1038: addInvokevirtual(constPool.addClassInfo(clazz), name, desc);
1039: }
1040:
1041: /**
1042: * Appends INVOKEVIRTUAL.
1043: *
1044: * <p>The specified method must not be an inherited method.
1045: * It must be directly declared in the class specified
1046: * in <code>classname</code>.
1047: *
1048: * @param classname the fully-qualified class name.
1049: * @param name the method name
1050: * @param desc the descriptor of the method signature.
1051: *
1052: * @see Descriptor#ofMethod(CtClass,CtClass[])
1053: */
1054: public void addInvokevirtual(String classname, String name,
1055: String desc) {
1056: addInvokevirtual(constPool.addClassInfo(classname), name, desc);
1057: }
1058:
1059: /**
1060: * Appends INVOKEVIRTUAL.
1061: *
1062: * <p>The specified method must not be an inherited method.
1063: * It must be directly declared in the class specified
1064: * by <code>clazz</code>.
1065: *
1066: * @param clazz the index of <code>CONSTANT_Class_info</code>
1067: * structure.
1068: * @param name the method name
1069: * @param desc the descriptor of the method signature.
1070: *
1071: * @see Descriptor#ofMethod(CtClass,CtClass[])
1072: */
1073: public void addInvokevirtual(int clazz, String name, String desc) {
1074: add(INVOKEVIRTUAL);
1075: addIndex(constPool.addMethodrefInfo(clazz, name, desc));
1076: growStack(Descriptor.dataSize(desc) - 1);
1077: }
1078:
1079: /**
1080: * Appends INVOKEINTERFACE.
1081: *
1082: * @param clazz the target class.
1083: * @param name the method name
1084: * @param returnType the return type.
1085: * @param paramTypes the parameter types.
1086: * @param count the count operand of the instruction.
1087: */
1088: public void addInvokeinterface(CtClass clazz, String name,
1089: CtClass returnType, CtClass[] paramTypes, int count) {
1090: String desc = Descriptor.ofMethod(returnType, paramTypes);
1091: addInvokeinterface(clazz, name, desc, count);
1092: }
1093:
1094: /**
1095: * Appends INVOKEINTERFACE.
1096: *
1097: * @param clazz the target class.
1098: * @param name the method name
1099: * @param desc the descriptor of the method signature.
1100: * @param count the count operand of the instruction.
1101: *
1102: * @see Descriptor#ofMethod(CtClass,CtClass[])
1103: */
1104: public void addInvokeinterface(CtClass clazz, String name,
1105: String desc, int count) {
1106: addInvokeinterface(constPool.addClassInfo(clazz), name, desc,
1107: count);
1108: }
1109:
1110: /**
1111: * Appends INVOKEINTERFACE.
1112: *
1113: * @param classname the fully-qualified class name.
1114: * @param name the method name
1115: * @param desc the descriptor of the method signature.
1116: * @param count the count operand of the instruction.
1117: *
1118: * @see Descriptor#ofMethod(CtClass,CtClass[])
1119: */
1120: public void addInvokeinterface(String classname, String name,
1121: String desc, int count) {
1122: addInvokeinterface(constPool.addClassInfo(classname), name,
1123: desc, count);
1124: }
1125:
1126: /**
1127: * Appends INVOKEINTERFACE.
1128: *
1129: * @param clazz the index of <code>CONSTANT_Class_info</code>
1130: * structure.
1131: * @param name the method name
1132: * @param desc the descriptor of the method signature.
1133: * @param count the count operand of the instruction.
1134: *
1135: * @see Descriptor#ofMethod(CtClass,CtClass[])
1136: */
1137: public void addInvokeinterface(int clazz, String name, String desc,
1138: int count) {
1139: add(INVOKEINTERFACE);
1140: addIndex(constPool.addInterfaceMethodrefInfo(clazz, name, desc));
1141: add(count);
1142: add(0);
1143: growStack(Descriptor.dataSize(desc) - 1);
1144: }
1145:
1146: /**
1147: * Appends LDC or LDC_W. The pushed item is a <code>String</code>
1148: * object.
1149: *
1150: * @param s the character string pushed by LDC or LDC_W.
1151: */
1152: public void addLdc(String s) {
1153: addLdc(constPool.addStringInfo(s));
1154: }
1155:
1156: /**
1157: * Appends LDC or LDC_W.
1158: *
1159: * @param i index into the constant pool.
1160: */
1161: public void addLdc(int i) {
1162: if (i > 0xFF) {
1163: addOpcode(LDC_W);
1164: addIndex(i);
1165: } else {
1166: addOpcode(LDC);
1167: add(i);
1168: }
1169: }
1170:
1171: /**
1172: * Appends LDC2_W. The pushed item is a long value.
1173: */
1174: public void addLdc2w(long l) {
1175: addOpcode(LDC2_W);
1176: addIndex(constPool.addLongInfo(l));
1177: }
1178:
1179: /**
1180: * Appends LDC2_W. The pushed item is a double value.
1181: */
1182: public void addLdc2w(double d) {
1183: addOpcode(LDC2_W);
1184: addIndex(constPool.addDoubleInfo(d));
1185: }
1186:
1187: /**
1188: * Appends NEW.
1189: *
1190: * @param clazz the class of the created instance.
1191: */
1192: public void addNew(CtClass clazz) {
1193: addOpcode(NEW);
1194: addIndex(constPool.addClassInfo(clazz));
1195: }
1196:
1197: /**
1198: * Appends NEW.
1199: *
1200: * @param classname the fully-qualified class name.
1201: */
1202: public void addNew(String classname) {
1203: addOpcode(NEW);
1204: addIndex(constPool.addClassInfo(classname));
1205: }
1206:
1207: /**
1208: * Appends ANEWARRAY.
1209: *
1210: * @param classname the qualified class name of the element type.
1211: */
1212: public void addAnewarray(String classname) {
1213: addOpcode(ANEWARRAY);
1214: addIndex(constPool.addClassInfo(classname));
1215: }
1216:
1217: /**
1218: * Appends ICONST and ANEWARRAY.
1219: *
1220: * @param clazz the elememnt type.
1221: * @param length the array length.
1222: */
1223: public void addAnewarray(CtClass clazz, int length) {
1224: addIconst(length);
1225: addOpcode(ANEWARRAY);
1226: addIndex(constPool.addClassInfo(clazz));
1227: }
1228:
1229: /**
1230: * Appends NEWARRAY for primitive types.
1231: *
1232: * @param atype <code>T_BOOLEAN</code>, <code>T_CHAR</code>, ...
1233: * @see Opcode
1234: */
1235: public void addNewarray(int atype, int length) {
1236: addIconst(length);
1237: addOpcode(NEWARRAY);
1238: add(atype);
1239: }
1240:
1241: /**
1242: * Appends MULTINEWARRAY.
1243: *
1244: * @param clazz the array type.
1245: * @param dimensions the sizes of all dimensions.
1246: * @return the length of <code>dimensions</code>.
1247: */
1248: public int addMultiNewarray(CtClass clazz, int[] dimensions) {
1249: int len = dimensions.length;
1250: for (int i = 0; i < len; ++i)
1251: addIconst(dimensions[i]);
1252:
1253: growStack(len);
1254: return addMultiNewarray(clazz, len);
1255: }
1256:
1257: /**
1258: * Appends MULTINEWARRAY. The size of every dimension must have been
1259: * already pushed on the stack.
1260: *
1261: * @param clazz the array type.
1262: * @param dim the number of the dimensions.
1263: * @return the value of <code>dim</code>.
1264: */
1265: public int addMultiNewarray(CtClass clazz, int dim) {
1266: add(MULTIANEWARRAY);
1267: addIndex(constPool.addClassInfo(clazz));
1268: add(dim);
1269: growStack(1 - dim);
1270: return dim;
1271: }
1272:
1273: /**
1274: * Appends MULTINEWARRAY.
1275: *
1276: * @param desc the type descriptor of the created array.
1277: * @param dim dimensions.
1278: * @return the value of <code>dim</code>.
1279: */
1280: public int addMultiNewarray(String desc, int dim) {
1281: add(MULTIANEWARRAY);
1282: addIndex(constPool.addClassInfo(desc));
1283: add(dim);
1284: growStack(1 - dim);
1285: return dim;
1286: }
1287:
1288: /**
1289: * Appends PUTFIELD.
1290: *
1291: * @param c the target class.
1292: * @param name the field name.
1293: * @param desc the descriptor of the field type.
1294: */
1295: public void addPutfield(CtClass c, String name, String desc) {
1296: addPutfield0(c, null, name, desc);
1297: }
1298:
1299: /**
1300: * Appends PUTFIELD.
1301: *
1302: * @param classname the fully-qualified name of the target class.
1303: * @param name the field name.
1304: * @param desc the descriptor of the field type.
1305: */
1306: public void addPutfield(String classname, String name, String desc) {
1307: // if classnaem is null, the target class is THIS.
1308: addPutfield0(null, classname, name, desc);
1309: }
1310:
1311: private void addPutfield0(CtClass target, String classname,
1312: String name, String desc) {
1313: add(PUTFIELD);
1314: // target is null if it represents THIS.
1315: int ci = classname == null ? constPool.addClassInfo(target)
1316: : constPool.addClassInfo(classname);
1317: addIndex(constPool.addFieldrefInfo(ci, name, desc));
1318: growStack(-1 - Descriptor.dataSize(desc));
1319: }
1320:
1321: /**
1322: * Appends PUTSTATIC.
1323: *
1324: * @param c the target class.
1325: * @param name the field name.
1326: * @param desc the descriptor of the field type.
1327: */
1328: public void addPutstatic(CtClass c, String name, String desc) {
1329: addPutstatic0(c, null, name, desc);
1330: }
1331:
1332: /**
1333: * Appends PUTSTATIC.
1334: *
1335: * @param classname the fully-qualified name of the target class.
1336: * @param fieldName the field name.
1337: * @param desc the descriptor of the field type.
1338: */
1339: public void addPutstatic(String classname, String fieldName,
1340: String desc) {
1341: // if classname is null, the target class is THIS.
1342: addPutstatic0(null, classname, fieldName, desc);
1343: }
1344:
1345: private void addPutstatic0(CtClass target, String classname,
1346: String fieldName, String desc) {
1347: add(PUTSTATIC);
1348: // target is null if it represents THIS.
1349: int ci = classname == null ? constPool.addClassInfo(target)
1350: : constPool.addClassInfo(classname);
1351: addIndex(constPool.addFieldrefInfo(ci, fieldName, desc));
1352: growStack(-Descriptor.dataSize(desc));
1353: }
1354:
1355: /**
1356: * Appends ARETURN, IRETURN, .., or RETURN.
1357: *
1358: * @param type the return type.
1359: */
1360: public void addReturn(CtClass type) {
1361: if (type == null)
1362: addOpcode(RETURN);
1363: else if (type.isPrimitive()) {
1364: CtPrimitiveType ptype = (CtPrimitiveType) type;
1365: addOpcode(ptype.getReturnOp());
1366: } else
1367: addOpcode(ARETURN);
1368: }
1369:
1370: /**
1371: * Appends RET.
1372: *
1373: * @param var local variable
1374: */
1375: public void addRet(int var) {
1376: if (var < 0x100) {
1377: addOpcode(RET);
1378: add(var);
1379: } else {
1380: addOpcode(WIDE);
1381: addOpcode(RET);
1382: addIndex(var);
1383: }
1384: }
1385:
1386: /**
1387: * Appends instructions for executing
1388: * <code>java.lang.System.println(<i>message</i>)</code>.
1389: *
1390: * @param message printed message.
1391: */
1392: public void addPrintln(String message) {
1393: addGetstatic("java.lang.System", "err", "Ljava/io/PrintStream;");
1394: addLdc(message);
1395: addInvokevirtual("java.io.PrintStream", "println",
1396: "(Ljava/lang/String;)V");
1397: }
1398: }
|