001: /***
002: * ASM: a very small and fast Java bytecode manipulation framework
003: * Copyright (c) 2000-2005 INRIA, France Telecom
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package com.tc.asm;
030:
031: import java.lang.reflect.Constructor;
032: import java.lang.reflect.Method;
033:
034: /**
035: * A Java type. This class can be used to make it easier to manipulate type and
036: * method descriptors.
037: *
038: * @author Eric Bruneton
039: * @author Chris Nokleberg
040: */
041: public class Type {
042:
043: /**
044: * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
045: */
046: public final static int VOID = 0;
047:
048: /**
049: * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
050: */
051: public final static int BOOLEAN = 1;
052:
053: /**
054: * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
055: */
056: public final static int CHAR = 2;
057:
058: /**
059: * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
060: */
061: public final static int BYTE = 3;
062:
063: /**
064: * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
065: */
066: public final static int SHORT = 4;
067:
068: /**
069: * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
070: */
071: public final static int INT = 5;
072:
073: /**
074: * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
075: */
076: public final static int FLOAT = 6;
077:
078: /**
079: * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
080: */
081: public final static int LONG = 7;
082:
083: /**
084: * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
085: */
086: public final static int DOUBLE = 8;
087:
088: /**
089: * The sort of array reference types. See {@link #getSort getSort}.
090: */
091: public final static int ARRAY = 9;
092:
093: /**
094: * The sort of object reference type. See {@link #getSort getSort}.
095: */
096: public final static int OBJECT = 10;
097:
098: /**
099: * The <tt>void</tt> type.
100: */
101: public final static Type VOID_TYPE = new Type(VOID);
102:
103: /**
104: * The <tt>boolean</tt> type.
105: */
106: public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
107:
108: /**
109: * The <tt>char</tt> type.
110: */
111: public final static Type CHAR_TYPE = new Type(CHAR);
112:
113: /**
114: * The <tt>byte</tt> type.
115: */
116: public final static Type BYTE_TYPE = new Type(BYTE);
117:
118: /**
119: * The <tt>short</tt> type.
120: */
121: public final static Type SHORT_TYPE = new Type(SHORT);
122:
123: /**
124: * The <tt>int</tt> type.
125: */
126: public final static Type INT_TYPE = new Type(INT);
127:
128: /**
129: * The <tt>float</tt> type.
130: */
131: public final static Type FLOAT_TYPE = new Type(FLOAT);
132:
133: /**
134: * The <tt>long</tt> type.
135: */
136: public final static Type LONG_TYPE = new Type(LONG);
137:
138: /**
139: * The <tt>double</tt> type.
140: */
141: public final static Type DOUBLE_TYPE = new Type(DOUBLE);
142:
143: // ------------------------------------------------------------------------
144: // Fields
145: // ------------------------------------------------------------------------
146:
147: /**
148: * The sort of this Java type.
149: */
150: private final int sort;
151:
152: /**
153: * A buffer containing the descriptor of this Java type. This field is only
154: * used for reference types.
155: */
156: private char[] buf;
157:
158: /**
159: * The offset of the descriptor of this Java type in {@link #buf buf}. This
160: * field is only used for reference types.
161: */
162: private int off;
163:
164: /**
165: * The length of the descriptor of this Java type.
166: */
167: private int len;
168:
169: // ------------------------------------------------------------------------
170: // Constructors
171: // ------------------------------------------------------------------------
172:
173: /**
174: * Constructs a primitive type.
175: *
176: * @param sort the sort of the primitive type to be constructed.
177: */
178: private Type(final int sort) {
179: this .sort = sort;
180: this .len = 1;
181: }
182:
183: /**
184: * Constructs a reference type.
185: *
186: * @param sort the sort of the reference type to be constructed.
187: * @param buf a buffer containing the descriptor of the previous type.
188: * @param off the offset of this descriptor in the previous buffer.
189: * @param len the length of this descriptor.
190: */
191: private Type(final int sort, final char[] buf, final int off,
192: final int len) {
193: this .sort = sort;
194: this .buf = buf;
195: this .off = off;
196: this .len = len;
197: }
198:
199: /**
200: * Returns the Java type corresponding to the given type descriptor.
201: *
202: * @param typeDescriptor a type descriptor.
203: * @return the Java type corresponding to the given type descriptor.
204: */
205: public static Type getType(final String typeDescriptor) {
206: return getType(typeDescriptor.toCharArray(), 0);
207: }
208:
209: /**
210: * Returns the Java type corresponding to the given class.
211: *
212: * @param c a class.
213: * @return the Java type corresponding to the given class.
214: */
215: public static Type getType(final Class c) {
216: if (c.isPrimitive()) {
217: if (c == Integer.TYPE) {
218: return INT_TYPE;
219: } else if (c == Void.TYPE) {
220: return VOID_TYPE;
221: } else if (c == Boolean.TYPE) {
222: return BOOLEAN_TYPE;
223: } else if (c == Byte.TYPE) {
224: return BYTE_TYPE;
225: } else if (c == Character.TYPE) {
226: return CHAR_TYPE;
227: } else if (c == Short.TYPE) {
228: return SHORT_TYPE;
229: } else if (c == Double.TYPE) {
230: return DOUBLE_TYPE;
231: } else if (c == Float.TYPE) {
232: return FLOAT_TYPE;
233: } else /* if (c == Long.TYPE) */{
234: return LONG_TYPE;
235: }
236: } else {
237: return getType(getDescriptor(c));
238: }
239: }
240:
241: /**
242: * Returns the {@link Type#OBJECT} type for the given internal class name.
243: * This is a shortcut method for <code>Type.getType("L"+name+";")</code>.
244: * <i>Note that opposed to {@link Type#getType(String)}, this method takes
245: * internal class names and not class descriptor.</i>
246: *
247: * @param name an internal class name.
248: * @return the the {@link Type#OBJECT} type for the given class name.
249: */
250: public static Type getObjectType(String name) {
251: int l = name.length();
252: char[] buf = new char[l + 2];
253: buf[0] = 'L';
254: buf[l + 1] = ';';
255: name.getChars(0, l, buf, 1);
256: return new Type(OBJECT, buf, 0, l + 2);
257: }
258:
259: /**
260: * Returns the Java types corresponding to the argument types of the given
261: * method descriptor.
262: *
263: * @param methodDescriptor a method descriptor.
264: * @return the Java types corresponding to the argument types of the given
265: * method descriptor.
266: */
267: public static Type[] getArgumentTypes(final String methodDescriptor) {
268: char[] buf = methodDescriptor.toCharArray();
269: int off = 1;
270: int size = 0;
271: while (true) {
272: char car = buf[off++];
273: if (car == ')') {
274: break;
275: } else if (car == 'L') {
276: while (buf[off++] != ';') {
277: }
278: ++size;
279: } else if (car != '[') {
280: ++size;
281: }
282: }
283: Type[] args = new Type[size];
284: off = 1;
285: size = 0;
286: while (buf[off] != ')') {
287: args[size] = getType(buf, off);
288: off += args[size].len;
289: size += 1;
290: }
291: return args;
292: }
293:
294: /**
295: * Returns the Java types corresponding to the argument types of the given
296: * method.
297: *
298: * @param method a method.
299: * @return the Java types corresponding to the argument types of the given
300: * method.
301: */
302: public static Type[] getArgumentTypes(final Method method) {
303: Class[] classes = method.getParameterTypes();
304: Type[] types = new Type[classes.length];
305: for (int i = classes.length - 1; i >= 0; --i) {
306: types[i] = getType(classes[i]);
307: }
308: return types;
309: }
310:
311: /**
312: * Returns the Java type corresponding to the return type of the given
313: * method descriptor.
314: *
315: * @param methodDescriptor a method descriptor.
316: * @return the Java type corresponding to the return type of the given
317: * method descriptor.
318: */
319: public static Type getReturnType(final String methodDescriptor) {
320: char[] buf = methodDescriptor.toCharArray();
321: return getType(buf, methodDescriptor.indexOf(')') + 1);
322: }
323:
324: /**
325: * Returns the Java type corresponding to the return type of the given
326: * method.
327: *
328: * @param method a method.
329: * @return the Java type corresponding to the return type of the given
330: * method.
331: */
332: public static Type getReturnType(final Method method) {
333: return getType(method.getReturnType());
334: }
335:
336: /**
337: * Returns the Java type corresponding to the given type descriptor.
338: *
339: * @param buf a buffer containing a type descriptor.
340: * @param off the offset of this descriptor in the previous buffer.
341: * @return the Java type corresponding to the given type descriptor.
342: */
343: private static Type getType(final char[] buf, final int off) {
344: int len;
345: switch (buf[off]) {
346: case 'V':
347: return VOID_TYPE;
348: case 'Z':
349: return BOOLEAN_TYPE;
350: case 'C':
351: return CHAR_TYPE;
352: case 'B':
353: return BYTE_TYPE;
354: case 'S':
355: return SHORT_TYPE;
356: case 'I':
357: return INT_TYPE;
358: case 'F':
359: return FLOAT_TYPE;
360: case 'J':
361: return LONG_TYPE;
362: case 'D':
363: return DOUBLE_TYPE;
364: case '[':
365: len = 1;
366: while (buf[off + len] == '[') {
367: ++len;
368: }
369: if (buf[off + len] == 'L') {
370: ++len;
371: while (buf[off + len] != ';') {
372: ++len;
373: }
374: }
375: return new Type(ARRAY, buf, off, len + 1);
376: // case 'L':
377: default:
378: len = 1;
379: while (buf[off + len] != ';') {
380: ++len;
381: }
382: return new Type(OBJECT, buf, off, len + 1);
383: }
384: }
385:
386: // ------------------------------------------------------------------------
387: // Accessors
388: // ------------------------------------------------------------------------
389:
390: /**
391: * Returns the sort of this Java type.
392: *
393: * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
394: * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
395: * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
396: * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or
397: * {@link #OBJECT OBJECT}.
398: */
399: public int getSort() {
400: return sort;
401: }
402:
403: /**
404: * Returns the number of dimensions of this array type. This method should
405: * only be used for an array type.
406: *
407: * @return the number of dimensions of this array type.
408: */
409: public int getDimensions() {
410: int i = 1;
411: while (buf[off + i] == '[') {
412: ++i;
413: }
414: return i;
415: }
416:
417: /**
418: * Returns the type of the elements of this array type. This method should
419: * only be used for an array type.
420: *
421: * @return Returns the type of the elements of this array type.
422: */
423: public Type getElementType() {
424: return getType(buf, off + getDimensions());
425: }
426:
427: /**
428: * Returns the name of the class corresponding to this type.
429: *
430: * @return the fully qualified name of the class corresponding to this type.
431: */
432: public String getClassName() {
433: switch (sort) {
434: case VOID:
435: return "void";
436: case BOOLEAN:
437: return "boolean";
438: case CHAR:
439: return "char";
440: case BYTE:
441: return "byte";
442: case SHORT:
443: return "short";
444: case INT:
445: return "int";
446: case FLOAT:
447: return "float";
448: case LONG:
449: return "long";
450: case DOUBLE:
451: return "double";
452: case ARRAY:
453: StringBuffer b = new StringBuffer(getElementType()
454: .getClassName());
455: for (int i = getDimensions(); i > 0; --i) {
456: b.append("[]");
457: }
458: return b.toString();
459: // case OBJECT:
460: default:
461: return new String(buf, off + 1, len - 2).replace('/', '.');
462: }
463: }
464:
465: /**
466: * Returns the internal name of the class corresponding to this object type.
467: * The internal name of a class is its fully qualified name, where '.' are
468: * replaced by '/'. This method should only be used for an object type.
469: *
470: * @return the internal name of the class corresponding to this object type.
471: */
472: public String getInternalName() {
473: return new String(buf, off + 1, len - 2);
474: }
475:
476: // ------------------------------------------------------------------------
477: // Conversion to type descriptors
478: // ------------------------------------------------------------------------
479:
480: /**
481: * Returns the descriptor corresponding to this Java type.
482: *
483: * @return the descriptor corresponding to this Java type.
484: */
485: public String getDescriptor() {
486: StringBuffer buf = new StringBuffer();
487: getDescriptor(buf);
488: return buf.toString();
489: }
490:
491: /**
492: * Returns the descriptor corresponding to the given argument and return
493: * types.
494: *
495: * @param returnType the return type of the method.
496: * @param argumentTypes the argument types of the method.
497: * @return the descriptor corresponding to the given argument and return
498: * types.
499: */
500: public static String getMethodDescriptor(final Type returnType,
501: final Type[] argumentTypes) {
502: StringBuffer buf = new StringBuffer();
503: buf.append('(');
504: for (int i = 0; i < argumentTypes.length; ++i) {
505: argumentTypes[i].getDescriptor(buf);
506: }
507: buf.append(')');
508: returnType.getDescriptor(buf);
509: return buf.toString();
510: }
511:
512: /**
513: * Appends the descriptor corresponding to this Java type to the given
514: * string buffer.
515: *
516: * @param buf the string buffer to which the descriptor must be appended.
517: */
518: private void getDescriptor(final StringBuffer buf) {
519: switch (sort) {
520: case VOID:
521: buf.append('V');
522: return;
523: case BOOLEAN:
524: buf.append('Z');
525: return;
526: case CHAR:
527: buf.append('C');
528: return;
529: case BYTE:
530: buf.append('B');
531: return;
532: case SHORT:
533: buf.append('S');
534: return;
535: case INT:
536: buf.append('I');
537: return;
538: case FLOAT:
539: buf.append('F');
540: return;
541: case LONG:
542: buf.append('J');
543: return;
544: case DOUBLE:
545: buf.append('D');
546: return;
547: // case ARRAY:
548: // case OBJECT:
549: default:
550: buf.append(this .buf, off, len);
551: }
552: }
553:
554: // ------------------------------------------------------------------------
555: // Direct conversion from classes to type descriptors,
556: // without intermediate Type objects
557: // ------------------------------------------------------------------------
558:
559: /**
560: * Returns the internal name of the given class. The internal name of a
561: * class is its fully qualified name, where '.' are replaced by '/'.
562: *
563: * @param c an object class.
564: * @return the internal name of the given class.
565: */
566: public static String getInternalName(final Class c) {
567: return c.getName().replace('.', '/');
568: }
569:
570: /**
571: * Returns the descriptor corresponding to the given Java type.
572: *
573: * @param c an object class, a primitive class or an array class.
574: * @return the descriptor corresponding to the given class.
575: */
576: public static String getDescriptor(final Class c) {
577: StringBuffer buf = new StringBuffer();
578: getDescriptor(buf, c);
579: return buf.toString();
580: }
581:
582: /**
583: * Returns the descriptor corresponding to the given constructor.
584: *
585: * @param c a {@link Constructor Constructor} object.
586: * @return the descriptor of the given constructor.
587: */
588: public static String getConstructorDescriptor(final Constructor c) {
589: Class[] parameters = c.getParameterTypes();
590: StringBuffer buf = new StringBuffer();
591: buf.append('(');
592: for (int i = 0; i < parameters.length; ++i) {
593: getDescriptor(buf, parameters[i]);
594: }
595: return buf.append(")V").toString();
596: }
597:
598: /**
599: * Returns the descriptor corresponding to the given method.
600: *
601: * @param m a {@link Method Method} object.
602: * @return the descriptor of the given method.
603: */
604: public static String getMethodDescriptor(final Method m) {
605: Class[] parameters = m.getParameterTypes();
606: StringBuffer buf = new StringBuffer();
607: buf.append('(');
608: for (int i = 0; i < parameters.length; ++i) {
609: getDescriptor(buf, parameters[i]);
610: }
611: buf.append(')');
612: getDescriptor(buf, m.getReturnType());
613: return buf.toString();
614: }
615:
616: /**
617: * Appends the descriptor of the given class to the given string buffer.
618: *
619: * @param buf the string buffer to which the descriptor must be appended.
620: * @param c the class whose descriptor must be computed.
621: */
622: private static void getDescriptor(final StringBuffer buf,
623: final Class c) {
624: Class d = c;
625: while (true) {
626: if (d.isPrimitive()) {
627: char car;
628: if (d == Integer.TYPE) {
629: car = 'I';
630: } else if (d == Void.TYPE) {
631: car = 'V';
632: } else if (d == Boolean.TYPE) {
633: car = 'Z';
634: } else if (d == Byte.TYPE) {
635: car = 'B';
636: } else if (d == Character.TYPE) {
637: car = 'C';
638: } else if (d == Short.TYPE) {
639: car = 'S';
640: } else if (d == Double.TYPE) {
641: car = 'D';
642: } else if (d == Float.TYPE) {
643: car = 'F';
644: } else /* if (d == Long.TYPE) */{
645: car = 'J';
646: }
647: buf.append(car);
648: return;
649: } else if (d.isArray()) {
650: buf.append('[');
651: d = d.getComponentType();
652: } else {
653: buf.append('L');
654: String name = d.getName();
655: int len = name.length();
656: for (int i = 0; i < len; ++i) {
657: char car = name.charAt(i);
658: buf.append(car == '.' ? '/' : car);
659: }
660: buf.append(';');
661: return;
662: }
663: }
664: }
665:
666: // ------------------------------------------------------------------------
667: // Corresponding size and opcodes
668: // ------------------------------------------------------------------------
669:
670: /**
671: * Returns the size of values of this type.
672: *
673: * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
674: * <tt>double</tt>, and 1 otherwise.
675: */
676: public int getSize() {
677: return sort == LONG || sort == DOUBLE ? 2 : 1;
678: }
679:
680: /**
681: * Returns a JVM instruction opcode adapted to this Java type.
682: *
683: * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
684: * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
685: * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
686: * @return an opcode that is similar to the given opcode, but adapted to
687: * this Java type. For example, if this type is <tt>float</tt> and
688: * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
689: */
690: public int getOpcode(final int opcode) {
691: if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
692: switch (sort) {
693: case BOOLEAN:
694: case BYTE:
695: return opcode + 5;
696: case CHAR:
697: return opcode + 6;
698: case SHORT:
699: return opcode + 7;
700: case INT:
701: return opcode;
702: case FLOAT:
703: return opcode + 2;
704: case LONG:
705: return opcode + 1;
706: case DOUBLE:
707: return opcode + 3;
708: // case ARRAY:
709: // case OBJECT:
710: default:
711: return opcode + 4;
712: }
713: } else {
714: switch (sort) {
715: case VOID:
716: return opcode + 5;
717: case BOOLEAN:
718: case CHAR:
719: case BYTE:
720: case SHORT:
721: case INT:
722: return opcode;
723: case FLOAT:
724: return opcode + 2;
725: case LONG:
726: return opcode + 1;
727: case DOUBLE:
728: return opcode + 3;
729: // case ARRAY:
730: // case OBJECT:
731: default:
732: return opcode + 4;
733: }
734: }
735: }
736:
737: // ------------------------------------------------------------------------
738: // Equals, hashCode and toString
739: // ------------------------------------------------------------------------
740:
741: /**
742: * Tests if the given object is equal to this type.
743: *
744: * @param o the object to be compared to this type.
745: * @return <tt>true</tt> if the given object is equal to this type.
746: */
747: public boolean equals(final Object o) {
748: if (this == o) {
749: return true;
750: }
751: if (!(o instanceof Type)) {
752: return false;
753: }
754: Type t = (Type) o;
755: if (sort != t.sort) {
756: return false;
757: }
758: if (sort == Type.OBJECT || sort == Type.ARRAY) {
759: if (len != t.len) {
760: return false;
761: }
762: for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
763: if (buf[i] != t.buf[j]) {
764: return false;
765: }
766: }
767: }
768: return true;
769: }
770:
771: /**
772: * Returns a hash code value for this type.
773: *
774: * @return a hash code value for this type.
775: */
776: public int hashCode() {
777: int hc = 13 * sort;
778: if (sort == Type.OBJECT || sort == Type.ARRAY) {
779: for (int i = off, end = i + len; i < end; i++) {
780: hc = 17 * (hc + buf[i]);
781: }
782: }
783: return hc;
784: }
785:
786: /**
787: * Returns a string representation of this type.
788: *
789: * @return the descriptor of this type.
790: */
791: public String toString() {
792: return getDescriptor();
793: }
794: }
|