2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2011 INRIA, France Telecom
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
30 package com.sleepycat.asm;
32 import java.lang.reflect.Constructor;
33 import java.lang.reflect.Method;
36 * A Java field or method type. This class can be used to make it easier to
37 * manipulate type and method descriptors.
39 * @author Eric Bruneton
40 * @author Chris Nokleberg
45 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
47 public static final int VOID = 0;
50 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
52 public static final int BOOLEAN = 1;
55 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
57 public static final int CHAR = 2;
60 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
62 public static final int BYTE = 3;
65 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
67 public static final int SHORT = 4;
70 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
72 public static final int INT = 5;
75 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
77 public static final int FLOAT = 6;
80 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
82 public static final int LONG = 7;
85 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
87 public static final int DOUBLE = 8;
90 * The sort of array reference types. See {@link #getSort getSort}.
92 public static final int ARRAY = 9;
95 * The sort of object reference types. See {@link #getSort getSort}.
97 public static final int OBJECT = 10;
100 * The sort of method types. See {@link #getSort getSort}.
102 public static final int METHOD = 11;
105 * The <tt>void</tt> type.
107 public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
108 | (5 << 16) | (0 << 8) | 0, 1);
111 * The <tt>boolean</tt> type.
113 public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
114 | (0 << 16) | (5 << 8) | 1, 1);
117 * The <tt>char</tt> type.
119 public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
120 | (0 << 16) | (6 << 8) | 1, 1);
123 * The <tt>byte</tt> type.
125 public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
126 | (0 << 16) | (5 << 8) | 1, 1);
129 * The <tt>short</tt> type.
131 public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
132 | (0 << 16) | (7 << 8) | 1, 1);
135 * The <tt>int</tt> type.
137 public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
138 | (0 << 16) | (0 << 8) | 1, 1);
141 * The <tt>float</tt> type.
143 public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
144 | (2 << 16) | (2 << 8) | 1, 1);
147 * The <tt>long</tt> type.
149 public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
150 | (1 << 16) | (1 << 8) | 2, 1);
153 * The <tt>double</tt> type.
155 public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
156 | (3 << 16) | (3 << 8) | 2, 1);
158 // ------------------------------------------------------------------------
160 // ------------------------------------------------------------------------
163 * The sort of this Java type.
165 private final int sort;
168 * A buffer containing the internal name of this Java type. This field is
169 * only used for reference types.
171 private final char[] buf;
174 * The offset of the internal name of this Java type in {@link #buf buf} or,
175 * for primitive types, the size, descriptor and getOpcode offsets for this
176 * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
177 * for IALOAD or IASTORE, byte 3 the offset for all other instructions).
179 private final int off;
182 * The length of the internal name of this Java type.
184 private final int len;
186 // ------------------------------------------------------------------------
188 // ------------------------------------------------------------------------
191 * Constructs a reference type.
193 * @param sort the sort of the reference type to be constructed.
194 * @param buf a buffer containing the descriptor of the previous type.
195 * @param off the offset of this descriptor in the previous buffer.
196 * @param len the length of this descriptor.
198 private Type(final int sort, final char[] buf, final int off, final int len)
207 * Returns the Java type corresponding to the given type descriptor.
209 * @param typeDescriptor a field or method type descriptor.
210 * @return the Java type corresponding to the given type descriptor.
212 public static Type getType(final String typeDescriptor) {
213 return getType(typeDescriptor.toCharArray(), 0);
217 * Returns the Java type corresponding to the given internal name.
219 * @param internalName an internal name.
220 * @return the Java type corresponding to the given internal name.
222 public static Type getObjectType(final String internalName) {
223 char[] buf = internalName.toCharArray();
224 return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
228 * Returns the Java type corresponding to the given method descriptor.
229 * Equivalent to <code>Type.getType(methodDescriptor)</code>.
231 * @param methodDescriptor a method descriptor.
232 * @return the Java type corresponding to the given method descriptor.
234 public static Type getMethodType(final String methodDescriptor) {
235 return getType(methodDescriptor.toCharArray(), 0);
239 * Returns the Java method type corresponding to the given argument and
242 * @param returnType the return type of the method.
243 * @param argumentTypes the argument types of the method.
244 * @return the Java type corresponding to the given argument and return types.
246 public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
247 return getType(getMethodDescriptor(returnType, argumentTypes));
251 * Returns the Java type corresponding to the given class.
254 * @return the Java type corresponding to the given class.
256 public static Type getType(final Class<?> c) {
257 if (c.isPrimitive()) {
258 if (c == Integer.TYPE) {
260 } else if (c == Void.TYPE) {
262 } else if (c == Boolean.TYPE) {
264 } else if (c == Byte.TYPE) {
266 } else if (c == Character.TYPE) {
268 } else if (c == Short.TYPE) {
270 } else if (c == Double.TYPE) {
272 } else if (c == Float.TYPE) {
274 } else /* if (c == Long.TYPE) */{
278 return getType(getDescriptor(c));
283 * Returns the Java method type corresponding to the given constructor.
285 * @param c a {@link Constructor Constructor} object.
286 * @return the Java method type corresponding to the given constructor.
288 public static Type getType(final Constructor<?> c) {
289 return getType(getConstructorDescriptor(c));
293 * Returns the Java method type corresponding to the given method.
295 * @param m a {@link Method Method} object.
296 * @return the Java method type corresponding to the given method.
298 public static Type getType(final Method m) {
299 return getType(getMethodDescriptor(m));
303 * Returns the Java types corresponding to the argument types of the given
306 * @param methodDescriptor a method descriptor.
307 * @return the Java types corresponding to the argument types of the given
310 public static Type[] getArgumentTypes(final String methodDescriptor) {
311 char[] buf = methodDescriptor.toCharArray();
315 char car = buf[off++];
318 } else if (car == 'L') {
319 while (buf[off++] != ';') {
322 } else if (car != '[') {
326 Type[] args = new Type[size];
329 while (buf[off] != ')') {
330 args[size] = getType(buf, off);
331 off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
338 * Returns the Java types corresponding to the argument types of the given
341 * @param method a method.
342 * @return the Java types corresponding to the argument types of the given
345 public static Type[] getArgumentTypes(final Method method) {
346 Class<?>[] classes = method.getParameterTypes();
347 Type[] types = new Type[classes.length];
348 for (int i = classes.length - 1; i >= 0; --i) {
349 types[i] = getType(classes[i]);
355 * Returns the Java type corresponding to the return type of the given
358 * @param methodDescriptor a method descriptor.
359 * @return the Java type corresponding to the return type of the given
362 public static Type getReturnType(final String methodDescriptor) {
363 char[] buf = methodDescriptor.toCharArray();
364 return getType(buf, methodDescriptor.indexOf(')') + 1);
368 * Returns the Java type corresponding to the return type of the given
371 * @param method a method.
372 * @return the Java type corresponding to the return type of the given
375 public static Type getReturnType(final Method method) {
376 return getType(method.getReturnType());
380 * Computes the size of the arguments and of the return value of a method.
382 * @param desc the descriptor of a method.
383 * @return the size of the arguments of the method (plus one for the
384 * implicit this argument), argSize, and the size of its return
385 * value, retSize, packed into a single int i =
386 * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
387 * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
389 public static int getArgumentsAndReturnSizes(final String desc) {
393 char car = desc.charAt(c++);
395 car = desc.charAt(c);
397 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
398 } else if (car == 'L') {
399 while (desc.charAt(c++) != ';') {
402 } else if (car == '[') {
403 while ((car = desc.charAt(c)) == '[') {
406 if (car == 'D' || car == 'J') {
409 } else if (car == 'D' || car == 'J') {
418 * Returns the Java type corresponding to the given type descriptor. For
419 * method descriptors, buf is supposed to contain nothing more than the
422 * @param buf a buffer containing a type descriptor.
423 * @param off the offset of this descriptor in the previous buffer.
424 * @return the Java type corresponding to the given type descriptor.
426 private static Type getType(final char[] buf, final int off) {
449 while (buf[off + len] == '[') {
452 if (buf[off + len] == 'L') {
454 while (buf[off + len] != ';') {
458 return new Type(ARRAY, buf, off, len + 1);
461 while (buf[off + len] != ';') {
464 return new Type(OBJECT, buf, off + 1, len - 1);
467 return new Type(METHOD, buf, 0, buf.length);
471 // ------------------------------------------------------------------------
473 // ------------------------------------------------------------------------
476 * Returns the sort of this Java type.
478 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
479 * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
480 * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
481 * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY},
482 * {@link #OBJECT OBJECT} or {@link #METHOD METHOD}.
484 public int getSort() {
489 * Returns the number of dimensions of this array type. This method should
490 * only be used for an array type.
492 * @return the number of dimensions of this array type.
494 public int getDimensions() {
496 while (buf[off + i] == '[') {
503 * Returns the type of the elements of this array type. This method should
504 * only be used for an array type.
506 * @return Returns the type of the elements of this array type.
508 public Type getElementType() {
509 return getType(buf, off + getDimensions());
513 * Returns the binary name of the class corresponding to this type. This
514 * method must not be used on method types.
516 * @return the binary name of the class corresponding to this type.
518 public String getClassName() {
539 StringBuffer b = new StringBuffer(getElementType().getClassName());
540 for (int i = getDimensions(); i > 0; --i) {
545 return new String(buf, off, len).replace('/', '.');
552 * Returns the internal name of the class corresponding to this object or
553 * array type. The internal name of a class is its fully qualified name (as
554 * returned by Class.getName(), where '.' are replaced by '/'. This method
555 * should only be used for an object or array type.
557 * @return the internal name of the class corresponding to this object type.
559 public String getInternalName() {
560 return new String(buf, off, len);
564 * Returns the argument types of methods of this type. This method should
565 * only be used for method types.
567 * @return the argument types of methods of this type.
569 public Type[] getArgumentTypes() {
570 return getArgumentTypes(getDescriptor());
574 * Returns the return type of methods of this type. This method should only
575 * be used for method types.
577 * @return the return type of methods of this type.
579 public Type getReturnType() {
580 return getReturnType(getDescriptor());
584 * Returns the size of the arguments and of the return value of methods of
585 * this type. This method should only be used for method types.
587 * @return the size of the arguments (plus one for the implicit this
588 * argument), argSize, and the size of the return value, retSize,
589 * packed into a single int i = <tt>(argSize << 2) | retSize</tt>
590 * (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
591 * <tt>i & 0x03</tt>).
593 public int getArgumentsAndReturnSizes() {
594 return getArgumentsAndReturnSizes(getDescriptor());
597 // ------------------------------------------------------------------------
598 // Conversion to type descriptors
599 // ------------------------------------------------------------------------
602 * Returns the descriptor corresponding to this Java type.
604 * @return the descriptor corresponding to this Java type.
606 public String getDescriptor() {
607 StringBuffer buf = new StringBuffer();
609 return buf.toString();
613 * Returns the descriptor corresponding to the given argument and return
616 * @param returnType the return type of the method.
617 * @param argumentTypes the argument types of the method.
618 * @return the descriptor corresponding to the given argument and return
621 public static String getMethodDescriptor(
622 final Type returnType,
623 final Type... argumentTypes)
625 StringBuffer buf = new StringBuffer();
627 for (int i = 0; i < argumentTypes.length; ++i) {
628 argumentTypes[i].getDescriptor(buf);
631 returnType.getDescriptor(buf);
632 return buf.toString();
636 * Appends the descriptor corresponding to this Java type to the given
639 * @param buf the string buffer to which the descriptor must be appended.
641 private void getDescriptor(final StringBuffer buf) {
642 if (this.buf == null) {
643 // descriptor is in byte 3 of 'off' for primitive types (buf == null)
644 buf.append((char) ((off & 0xFF000000) >>> 24));
645 } else if (sort == OBJECT) {
647 buf.append(this.buf, off, len);
649 } else { // sort == ARRAY || sort == METHOD
650 buf.append(this.buf, off, len);
654 // ------------------------------------------------------------------------
655 // Direct conversion from classes to type descriptors,
656 // without intermediate Type objects
657 // ------------------------------------------------------------------------
660 * Returns the internal name of the given class. The internal name of a
661 * class is its fully qualified name, as returned by Class.getName(), where
662 * '.' are replaced by '/'.
664 * @param c an object or array class.
665 * @return the internal name of the given class.
667 public static String getInternalName(final Class<?> c) {
668 return c.getName().replace('.', '/');
672 * Returns the descriptor corresponding to the given Java type.
674 * @param c an object class, a primitive class or an array class.
675 * @return the descriptor corresponding to the given class.
677 public static String getDescriptor(final Class<?> c) {
678 StringBuffer buf = new StringBuffer();
679 getDescriptor(buf, c);
680 return buf.toString();
684 * Returns the descriptor corresponding to the given constructor.
686 * @param c a {@link Constructor Constructor} object.
687 * @return the descriptor of the given constructor.
689 public static String getConstructorDescriptor(final Constructor<?> c) {
690 Class<?>[] parameters = c.getParameterTypes();
691 StringBuffer buf = new StringBuffer();
693 for (int i = 0; i < parameters.length; ++i) {
694 getDescriptor(buf, parameters[i]);
696 return buf.append(")V").toString();
700 * Returns the descriptor corresponding to the given method.
702 * @param m a {@link Method Method} object.
703 * @return the descriptor of the given method.
705 public static String getMethodDescriptor(final Method m) {
706 Class<?>[] parameters = m.getParameterTypes();
707 StringBuffer buf = new StringBuffer();
709 for (int i = 0; i < parameters.length; ++i) {
710 getDescriptor(buf, parameters[i]);
713 getDescriptor(buf, m.getReturnType());
714 return buf.toString();
718 * Appends the descriptor of the given class to the given string buffer.
720 * @param buf the string buffer to which the descriptor must be appended.
721 * @param c the class whose descriptor must be computed.
723 private static void getDescriptor(final StringBuffer buf, final Class<?> c) {
726 if (d.isPrimitive()) {
728 if (d == Integer.TYPE) {
730 } else if (d == Void.TYPE) {
732 } else if (d == Boolean.TYPE) {
734 } else if (d == Byte.TYPE) {
736 } else if (d == Character.TYPE) {
738 } else if (d == Short.TYPE) {
740 } else if (d == Double.TYPE) {
742 } else if (d == Float.TYPE) {
744 } else /* if (d == Long.TYPE) */{
749 } else if (d.isArray()) {
751 d = d.getComponentType();
754 String name = d.getName();
755 int len = name.length();
756 for (int i = 0; i < len; ++i) {
757 char car = name.charAt(i);
758 buf.append(car == '.' ? '/' : car);
766 // ------------------------------------------------------------------------
767 // Corresponding size and opcodes
768 // ------------------------------------------------------------------------
771 * Returns the size of values of this type. This method must not be used for
774 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
775 * <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
777 public int getSize() {
778 // the size is in byte 0 of 'off' for primitive types (buf == null)
779 return buf == null ? (off & 0xFF) : 1;
783 * Returns a JVM instruction opcode adapted to this Java type. This method
784 * must not be used for method types.
786 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
787 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
788 * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
789 * @return an opcode that is similar to the given opcode, but adapted to
790 * this Java type. For example, if this type is <tt>float</tt> and
791 * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
793 public int getOpcode(final int opcode) {
794 if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
795 // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
796 // primitive types (buf == null)
797 return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
799 // the offset for other instructions is in byte 2 of 'off' for
800 // primitive types (buf == null)
801 return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
805 // ------------------------------------------------------------------------
806 // Equals, hashCode and toString
807 // ------------------------------------------------------------------------
810 * Tests if the given object is equal to this type.
812 * @param o the object to be compared to this type.
813 * @return <tt>true</tt> if the given object is equal to this type.
816 public boolean equals(final Object o) {
820 if (!(o instanceof Type)) {
824 if (sort != t.sort) {
831 for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
832 if (buf[i] != t.buf[j]) {
841 * Returns a hash code value for this type.
843 * @return a hash code value for this type.
846 public int hashCode() {
849 for (int i = off, end = i + len; i < end; i++) {
850 hc = 17 * (hc + buf[i]);
857 * Returns a string representation of this type.
859 * @return the descriptor of this type.
862 public String toString() {
863 return getDescriptor();