Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / lang / java / src / com / sleepycat / asm / Type.java
1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2011 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
17  *
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.
29  */
30 package com.sleepycat.asm;
31
32 import java.lang.reflect.Constructor;
33 import java.lang.reflect.Method;
34
35 /**
36  * A Java field or method type. This class can be used to make it easier to
37  * manipulate type and method descriptors.
38  *
39  * @author Eric Bruneton
40  * @author Chris Nokleberg
41  */
42 public class Type {
43
44     /**
45      * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
46      */
47     public static final int VOID = 0;
48
49     /**
50      * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
51      */
52     public static final int BOOLEAN = 1;
53
54     /**
55      * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
56      */
57     public static final int CHAR = 2;
58
59     /**
60      * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
61      */
62     public static final int BYTE = 3;
63
64     /**
65      * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
66      */
67     public static final int SHORT = 4;
68
69     /**
70      * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
71      */
72     public static final int INT = 5;
73
74     /**
75      * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
76      */
77     public static final int FLOAT = 6;
78
79     /**
80      * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
81      */
82     public static final int LONG = 7;
83
84     /**
85      * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
86      */
87     public static final int DOUBLE = 8;
88
89     /**
90      * The sort of array reference types. See {@link #getSort getSort}.
91      */
92     public static final int ARRAY = 9;
93
94     /**
95      * The sort of object reference types. See {@link #getSort getSort}.
96      */
97     public static final int OBJECT = 10;
98
99     /**
100      * The sort of method types. See {@link #getSort getSort}.
101      */
102     public static final int METHOD = 11;
103
104     /**
105      * The <tt>void</tt> type.
106      */
107     public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
108             | (5 << 16) | (0 << 8) | 0, 1);
109
110     /**
111      * The <tt>boolean</tt> type.
112      */
113     public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
114             | (0 << 16) | (5 << 8) | 1, 1);
115
116     /**
117      * The <tt>char</tt> type.
118      */
119     public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
120             | (0 << 16) | (6 << 8) | 1, 1);
121
122     /**
123      * The <tt>byte</tt> type.
124      */
125     public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
126             | (0 << 16) | (5 << 8) | 1, 1);
127
128     /**
129      * The <tt>short</tt> type.
130      */
131     public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
132             | (0 << 16) | (7 << 8) | 1, 1);
133
134     /**
135      * The <tt>int</tt> type.
136      */
137     public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
138             | (0 << 16) | (0 << 8) | 1, 1);
139
140     /**
141      * The <tt>float</tt> type.
142      */
143     public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
144             | (2 << 16) | (2 << 8) | 1, 1);
145
146     /**
147      * The <tt>long</tt> type.
148      */
149     public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
150             | (1 << 16) | (1 << 8) | 2, 1);
151
152     /**
153      * The <tt>double</tt> type.
154      */
155     public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
156             | (3 << 16) | (3 << 8) | 2, 1);
157
158     // ------------------------------------------------------------------------
159     // Fields
160     // ------------------------------------------------------------------------
161
162     /**
163      * The sort of this Java type.
164      */
165     private final int sort;
166
167     /**
168      * A buffer containing the internal name of this Java type. This field is
169      * only used for reference types.
170      */
171     private final char[] buf;
172
173     /**
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).
178      */
179     private final int off;
180
181     /**
182      * The length of the internal name of this Java type.
183      */
184     private final int len;
185
186     // ------------------------------------------------------------------------
187     // Constructors
188     // ------------------------------------------------------------------------
189
190     /**
191      * Constructs a reference type.
192      *
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.
197      */
198     private Type(final int sort, final char[] buf, final int off, final int len)
199     {
200         this.sort = sort;
201         this.buf = buf;
202         this.off = off;
203         this.len = len;
204     }
205
206     /**
207      * Returns the Java type corresponding to the given type descriptor.
208      *
209      * @param typeDescriptor a field or method type descriptor.
210      * @return the Java type corresponding to the given type descriptor.
211      */
212     public static Type getType(final String typeDescriptor) {
213         return getType(typeDescriptor.toCharArray(), 0);
214     }
215
216     /**
217      * Returns the Java type corresponding to the given internal name.
218      *
219      * @param internalName an internal name.
220      * @return the Java type corresponding to the given internal name.
221      */
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);
225     }
226
227     /**
228      * Returns the Java type corresponding to the given method descriptor.
229      * Equivalent to <code>Type.getType(methodDescriptor)</code>.
230      *
231      * @param methodDescriptor a method descriptor.
232      * @return the Java type corresponding to the given method descriptor.
233      */
234     public static Type getMethodType(final String methodDescriptor) {
235         return getType(methodDescriptor.toCharArray(), 0);
236     }
237
238     /**
239      * Returns the Java method type corresponding to the given argument and
240      * return types.
241      *
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.
245      */
246     public static Type getMethodType(final Type returnType, final Type... argumentTypes) {
247         return getType(getMethodDescriptor(returnType, argumentTypes));
248     }
249
250     /**
251      * Returns the Java type corresponding to the given class.
252      *
253      * @param c a class.
254      * @return the Java type corresponding to the given class.
255      */
256     public static Type getType(final Class<?> c) {
257         if (c.isPrimitive()) {
258             if (c == Integer.TYPE) {
259                 return INT_TYPE;
260             } else if (c == Void.TYPE) {
261                 return VOID_TYPE;
262             } else if (c == Boolean.TYPE) {
263                 return BOOLEAN_TYPE;
264             } else if (c == Byte.TYPE) {
265                 return BYTE_TYPE;
266             } else if (c == Character.TYPE) {
267                 return CHAR_TYPE;
268             } else if (c == Short.TYPE) {
269                 return SHORT_TYPE;
270             } else if (c == Double.TYPE) {
271                 return DOUBLE_TYPE;
272             } else if (c == Float.TYPE) {
273                 return FLOAT_TYPE;
274             } else /* if (c == Long.TYPE) */{
275                 return LONG_TYPE;
276             }
277         } else {
278             return getType(getDescriptor(c));
279         }
280     }
281
282     /**
283      * Returns the Java method type corresponding to the given constructor.
284      *
285      * @param c a {@link Constructor Constructor} object.
286      * @return the Java method type corresponding to the given constructor.
287      */
288     public static Type getType(final Constructor<?> c) {
289         return getType(getConstructorDescriptor(c));
290     }
291
292     /**
293      * Returns the Java method type corresponding to the given method.
294      *
295      * @param m a {@link Method Method} object.
296      * @return the Java method type corresponding to the given method.
297      */
298     public static Type getType(final Method m) {
299         return getType(getMethodDescriptor(m));
300     }
301
302     /**
303      * Returns the Java types corresponding to the argument types of the given
304      * method descriptor.
305      *
306      * @param methodDescriptor a method descriptor.
307      * @return the Java types corresponding to the argument types of the given
308      *         method descriptor.
309      */
310     public static Type[] getArgumentTypes(final String methodDescriptor) {
311         char[] buf = methodDescriptor.toCharArray();
312         int off = 1;
313         int size = 0;
314         while (true) {
315             char car = buf[off++];
316             if (car == ')') {
317                 break;
318             } else if (car == 'L') {
319                 while (buf[off++] != ';') {
320                 }
321                 ++size;
322             } else if (car != '[') {
323                 ++size;
324             }
325         }
326         Type[] args = new Type[size];
327         off = 1;
328         size = 0;
329         while (buf[off] != ')') {
330             args[size] = getType(buf, off);
331             off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
332             size += 1;
333         }
334         return args;
335     }
336
337     /**
338      * Returns the Java types corresponding to the argument types of the given
339      * method.
340      *
341      * @param method a method.
342      * @return the Java types corresponding to the argument types of the given
343      *         method.
344      */
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]);
350         }
351         return types;
352     }
353
354     /**
355      * Returns the Java type corresponding to the return type of the given
356      * method descriptor.
357      *
358      * @param methodDescriptor a method descriptor.
359      * @return the Java type corresponding to the return type of the given
360      *         method descriptor.
361      */
362     public static Type getReturnType(final String methodDescriptor) {
363         char[] buf = methodDescriptor.toCharArray();
364         return getType(buf, methodDescriptor.indexOf(')') + 1);
365     }
366
367     /**
368      * Returns the Java type corresponding to the return type of the given
369      * method.
370      *
371      * @param method a method.
372      * @return the Java type corresponding to the return type of the given
373      *         method.
374      */
375     public static Type getReturnType(final Method method) {
376         return getType(method.getReturnType());
377     }
378
379     /**
380      * Computes the size of the arguments and of the return value of a method.
381      *
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>).
388      */
389     public static int getArgumentsAndReturnSizes(final String desc) {
390         int n = 1;
391         int c = 1;
392         while (true) {
393             char car = desc.charAt(c++);
394             if (car == ')') {
395                 car = desc.charAt(c);
396                 return n << 2
397                         | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
398             } else if (car == 'L') {
399                 while (desc.charAt(c++) != ';') {
400                 }
401                 n += 1;
402             } else if (car == '[') {
403                 while ((car = desc.charAt(c)) == '[') {
404                     ++c;
405                 }
406                 if (car == 'D' || car == 'J') {
407                     n -= 1;
408                 }
409             } else if (car == 'D' || car == 'J') {
410                 n += 2;
411             } else {
412                 n += 1;
413             }
414         }
415     }
416
417     /**
418      * Returns the Java type corresponding to the given type descriptor. For
419      * method descriptors, buf is supposed to contain nothing more than the
420      * descriptor itself.
421      *
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.
425      */
426     private static Type getType(final char[] buf, final int off) {
427         int len;
428         switch (buf[off]) {
429             case 'V':
430                 return VOID_TYPE;
431             case 'Z':
432                 return BOOLEAN_TYPE;
433             case 'C':
434                 return CHAR_TYPE;
435             case 'B':
436                 return BYTE_TYPE;
437             case 'S':
438                 return SHORT_TYPE;
439             case 'I':
440                 return INT_TYPE;
441             case 'F':
442                 return FLOAT_TYPE;
443             case 'J':
444                 return LONG_TYPE;
445             case 'D':
446                 return DOUBLE_TYPE;
447             case '[':
448                 len = 1;
449                 while (buf[off + len] == '[') {
450                     ++len;
451                 }
452                 if (buf[off + len] == 'L') {
453                     ++len;
454                     while (buf[off + len] != ';') {
455                         ++len;
456                     }
457                 }
458                 return new Type(ARRAY, buf, off, len + 1);
459             case 'L':
460                 len = 1;
461                 while (buf[off + len] != ';') {
462                     ++len;
463                 }
464                 return new Type(OBJECT, buf, off + 1, len - 1);
465             // case '(':
466             default:
467                 return new Type(METHOD, buf, 0, buf.length);
468         }
469     }
470
471     // ------------------------------------------------------------------------
472     // Accessors
473     // ------------------------------------------------------------------------
474
475     /**
476      * Returns the sort of this Java type.
477      *
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}.
483      */
484     public int getSort() {
485         return sort;
486     }
487
488     /**
489      * Returns the number of dimensions of this array type. This method should
490      * only be used for an array type.
491      *
492      * @return the number of dimensions of this array type.
493      */
494     public int getDimensions() {
495         int i = 1;
496         while (buf[off + i] == '[') {
497             ++i;
498         }
499         return i;
500     }
501
502     /**
503      * Returns the type of the elements of this array type. This method should
504      * only be used for an array type.
505      *
506      * @return Returns the type of the elements of this array type.
507      */
508     public Type getElementType() {
509         return getType(buf, off + getDimensions());
510     }
511
512     /**
513      * Returns the binary name of the class corresponding to this type. This
514      * method must not be used on method types.
515      *
516      * @return the binary name of the class corresponding to this type.
517      */
518     public String getClassName() {
519         switch (sort) {
520             case VOID:
521                 return "void";
522             case BOOLEAN:
523                 return "boolean";
524             case CHAR:
525                 return "char";
526             case BYTE:
527                 return "byte";
528             case SHORT:
529                 return "short";
530             case INT:
531                 return "int";
532             case FLOAT:
533                 return "float";
534             case LONG:
535                 return "long";
536             case DOUBLE:
537                 return "double";
538             case ARRAY:
539                 StringBuffer b = new StringBuffer(getElementType().getClassName());
540                 for (int i = getDimensions(); i > 0; --i) {
541                     b.append("[]");
542                 }
543                 return b.toString();
544             case OBJECT:
545                 return new String(buf, off, len).replace('/', '.');
546             default:
547                 return null;
548         }
549     }
550
551     /**
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.
556      *
557      * @return the internal name of the class corresponding to this object type.
558      */
559     public String getInternalName() {
560         return new String(buf, off, len);
561     }
562
563     /**
564      * Returns the argument types of methods of this type. This method should
565      * only be used for method types.
566      *
567      * @return the argument types of methods of this type.
568      */
569     public Type[] getArgumentTypes() {
570         return getArgumentTypes(getDescriptor());
571     }
572
573     /**
574      * Returns the return type of methods of this type. This method should only
575      * be used for method types.
576      *
577      * @return the return type of methods of this type.
578      */
579     public Type getReturnType() {
580         return getReturnType(getDescriptor());
581     }
582
583     /**
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.
586      *
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>).
592      */
593     public int getArgumentsAndReturnSizes() {
594         return getArgumentsAndReturnSizes(getDescriptor());
595     }
596
597     // ------------------------------------------------------------------------
598     // Conversion to type descriptors
599     // ------------------------------------------------------------------------
600
601     /**
602      * Returns the descriptor corresponding to this Java type.
603      *
604      * @return the descriptor corresponding to this Java type.
605      */
606     public String getDescriptor() {
607         StringBuffer buf = new StringBuffer();
608         getDescriptor(buf);
609         return buf.toString();
610     }
611
612     /**
613      * Returns the descriptor corresponding to the given argument and return
614      * types.
615      *
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
619      *         types.
620      */
621     public static String getMethodDescriptor(
622         final Type returnType,
623         final Type... argumentTypes)
624     {
625         StringBuffer buf = new StringBuffer();
626         buf.append('(');
627         for (int i = 0; i < argumentTypes.length; ++i) {
628             argumentTypes[i].getDescriptor(buf);
629         }
630         buf.append(')');
631         returnType.getDescriptor(buf);
632         return buf.toString();
633     }
634
635     /**
636      * Appends the descriptor corresponding to this Java type to the given
637      * string buffer.
638      *
639      * @param buf the string buffer to which the descriptor must be appended.
640      */
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) {
646             buf.append('L');
647             buf.append(this.buf, off, len);
648             buf.append(';');
649         } else { // sort == ARRAY || sort == METHOD
650             buf.append(this.buf, off, len);
651         }
652     }
653
654     // ------------------------------------------------------------------------
655     // Direct conversion from classes to type descriptors,
656     // without intermediate Type objects
657     // ------------------------------------------------------------------------
658
659     /**
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 '/'.
663      *
664      * @param c an object or array class.
665      * @return the internal name of the given class.
666      */
667     public static String getInternalName(final Class<?> c) {
668         return c.getName().replace('.', '/');
669     }
670
671     /**
672      * Returns the descriptor corresponding to the given Java type.
673      *
674      * @param c an object class, a primitive class or an array class.
675      * @return the descriptor corresponding to the given class.
676      */
677     public static String getDescriptor(final Class<?> c) {
678         StringBuffer buf = new StringBuffer();
679         getDescriptor(buf, c);
680         return buf.toString();
681     }
682
683     /**
684      * Returns the descriptor corresponding to the given constructor.
685      *
686      * @param c a {@link Constructor Constructor} object.
687      * @return the descriptor of the given constructor.
688      */
689     public static String getConstructorDescriptor(final Constructor<?> c) {
690         Class<?>[] parameters = c.getParameterTypes();
691         StringBuffer buf = new StringBuffer();
692         buf.append('(');
693         for (int i = 0; i < parameters.length; ++i) {
694             getDescriptor(buf, parameters[i]);
695         }
696         return buf.append(")V").toString();
697     }
698
699     /**
700      * Returns the descriptor corresponding to the given method.
701      *
702      * @param m a {@link Method Method} object.
703      * @return the descriptor of the given method.
704      */
705     public static String getMethodDescriptor(final Method m) {
706         Class<?>[] parameters = m.getParameterTypes();
707         StringBuffer buf = new StringBuffer();
708         buf.append('(');
709         for (int i = 0; i < parameters.length; ++i) {
710             getDescriptor(buf, parameters[i]);
711         }
712         buf.append(')');
713         getDescriptor(buf, m.getReturnType());
714         return buf.toString();
715     }
716
717     /**
718      * Appends the descriptor of the given class to the given string buffer.
719      *
720      * @param buf the string buffer to which the descriptor must be appended.
721      * @param c the class whose descriptor must be computed.
722      */
723     private static void getDescriptor(final StringBuffer buf, final Class<?> c) {
724         Class<?> d = c;
725         while (true) {
726             if (d.isPrimitive()) {
727                 char car;
728                 if (d == Integer.TYPE) {
729                     car = 'I';
730                 } else if (d == Void.TYPE) {
731                     car = 'V';
732                 } else if (d == Boolean.TYPE) {
733                     car = 'Z';
734                 } else if (d == Byte.TYPE) {
735                     car = 'B';
736                 } else if (d == Character.TYPE) {
737                     car = 'C';
738                 } else if (d == Short.TYPE) {
739                     car = 'S';
740                 } else if (d == Double.TYPE) {
741                     car = 'D';
742                 } else if (d == Float.TYPE) {
743                     car = 'F';
744                 } else /* if (d == Long.TYPE) */{
745                     car = 'J';
746                 }
747                 buf.append(car);
748                 return;
749             } else if (d.isArray()) {
750                 buf.append('[');
751                 d = d.getComponentType();
752             } else {
753                 buf.append('L');
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);
759                 }
760                 buf.append(';');
761                 return;
762             }
763         }
764     }
765
766     // ------------------------------------------------------------------------
767     // Corresponding size and opcodes
768     // ------------------------------------------------------------------------
769
770     /**
771      * Returns the size of values of this type. This method must not be used for
772      * method types.
773      *
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.
776      */
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;
780     }
781
782     /**
783      * Returns a JVM instruction opcode adapted to this Java type. This method
784      * must not be used for method types.
785      *
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.
792      */
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);
798         } else {
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);
802         }
803     }
804
805     // ------------------------------------------------------------------------
806     // Equals, hashCode and toString
807     // ------------------------------------------------------------------------
808
809     /**
810      * Tests if the given object is equal to this type.
811      *
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.
814      */
815     @Override
816     public boolean equals(final Object o) {
817         if (this == o) {
818             return true;
819         }
820         if (!(o instanceof Type)) {
821             return false;
822         }
823         Type t = (Type) o;
824         if (sort != t.sort) {
825             return false;
826         }
827         if (sort >= ARRAY) {
828             if (len != t.len) {
829                 return false;
830             }
831             for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
832                 if (buf[i] != t.buf[j]) {
833                     return false;
834                 }
835             }
836         }
837         return true;
838     }
839
840     /**
841      * Returns a hash code value for this type.
842      *
843      * @return a hash code value for this type.
844      */
845     @Override
846     public int hashCode() {
847         int hc = 13 * sort;
848         if (sort >= ARRAY) {
849             for (int i = off, end = i + len; i < end; i++) {
850                 hc = 17 * (hc + buf[i]);
851             }
852         }
853         return hc;
854     }
855
856     /**
857      * Returns a string representation of this type.
858      *
859      * @return the descriptor of this type.
860      */
861     @Override
862     public String toString() {
863         return getDescriptor();
864     }
865 }