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 scala.tools.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();