1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25/*
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
29 * file:
30 *
31 * ASM: a very small and fast Java bytecode manipulation framework
32 * Copyright (c) 2000-2011 INRIA, France Telecom
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the copyright holders nor the names of its
44 *    contributors may be used to endorse or promote products derived from
45 *    this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57 * THE POSSIBILITY OF SUCH DAMAGE.
58 */
59package jdk.internal.org.objectweb.asm;
60
61import java.lang.reflect.Constructor;
62import java.lang.reflect.Method;
63
64/**
65 * A Java field or method type. This class can be used to make it easier to
66 * manipulate type and method descriptors.
67 *
68 * @author Eric Bruneton
69 * @author Chris Nokleberg
70 */
71public class Type {
72
73    /**
74     * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
75     */
76    public static final int VOID = 0;
77
78    /**
79     * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
80     */
81    public static final int BOOLEAN = 1;
82
83    /**
84     * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
85     */
86    public static final int CHAR = 2;
87
88    /**
89     * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
90     */
91    public static final int BYTE = 3;
92
93    /**
94     * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
95     */
96    public static final int SHORT = 4;
97
98    /**
99     * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
100     */
101    public static final int INT = 5;
102
103    /**
104     * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
105     */
106    public static final int FLOAT = 6;
107
108    /**
109     * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
110     */
111    public static final int LONG = 7;
112
113    /**
114     * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
115     */
116    public static final int DOUBLE = 8;
117
118    /**
119     * The sort of array reference types. See {@link #getSort getSort}.
120     */
121    public static final int ARRAY = 9;
122
123    /**
124     * The sort of object reference types. See {@link #getSort getSort}.
125     */
126    public static final int OBJECT = 10;
127
128    /**
129     * The sort of method types. See {@link #getSort getSort}.
130     */
131    public static final int METHOD = 11;
132
133    /**
134     * The <tt>void</tt> type.
135     */
136    public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
137            | (5 << 16) | (0 << 8) | 0, 1);
138
139    /**
140     * The <tt>boolean</tt> type.
141     */
142    public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
143            | (0 << 16) | (5 << 8) | 1, 1);
144
145    /**
146     * The <tt>char</tt> type.
147     */
148    public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
149            | (0 << 16) | (6 << 8) | 1, 1);
150
151    /**
152     * The <tt>byte</tt> type.
153     */
154    public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
155            | (0 << 16) | (5 << 8) | 1, 1);
156
157    /**
158     * The <tt>short</tt> type.
159     */
160    public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
161            | (0 << 16) | (7 << 8) | 1, 1);
162
163    /**
164     * The <tt>int</tt> type.
165     */
166    public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
167            | (0 << 16) | (0 << 8) | 1, 1);
168
169    /**
170     * The <tt>float</tt> type.
171     */
172    public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
173            | (2 << 16) | (2 << 8) | 1, 1);
174
175    /**
176     * The <tt>long</tt> type.
177     */
178    public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
179            | (1 << 16) | (1 << 8) | 2, 1);
180
181    /**
182     * The <tt>double</tt> type.
183     */
184    public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
185            | (3 << 16) | (3 << 8) | 2, 1);
186
187    // ------------------------------------------------------------------------
188    // Fields
189    // ------------------------------------------------------------------------
190
191    /**
192     * The sort of this Java type.
193     */
194    private final int sort;
195
196    /**
197     * A buffer containing the internal name of this Java type. This field is
198     * only used for reference types.
199     */
200    private final char[] buf;
201
202    /**
203     * The offset of the internal name of this Java type in {@link #buf buf} or,
204     * for primitive types, the size, descriptor and getOpcode offsets for this
205     * type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
206     * for IALOAD or IASTORE, byte 3 the offset for all other instructions).
207     */
208    private final int off;
209
210    /**
211     * The length of the internal name of this Java type.
212     */
213    private final int len;
214
215    // ------------------------------------------------------------------------
216    // Constructors
217    // ------------------------------------------------------------------------
218
219    /**
220     * Constructs a reference type.
221     *
222     * @param sort
223     *            the sort of the reference type to be constructed.
224     * @param buf
225     *            a buffer containing the descriptor of the previous type.
226     * @param off
227     *            the offset of this descriptor in the previous buffer.
228     * @param len
229     *            the length of this descriptor.
230     */
231    private Type(final int sort, final char[] buf, final int off, final int len) {
232        this.sort = sort;
233        this.buf = buf;
234        this.off = off;
235        this.len = len;
236    }
237
238    /**
239     * Returns the Java type corresponding to the given type descriptor.
240     *
241     * @param typeDescriptor
242     *            a field or method type descriptor.
243     * @return the Java type corresponding to the given type descriptor.
244     */
245    public static Type getType(final String typeDescriptor) {
246        return getType(typeDescriptor.toCharArray(), 0);
247    }
248
249    /**
250     * Returns the Java type corresponding to the given internal name.
251     *
252     * @param internalName
253     *            an internal name.
254     * @return the Java type corresponding to the given internal name.
255     */
256    public static Type getObjectType(final String internalName) {
257        char[] buf = internalName.toCharArray();
258        return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
259    }
260
261    /**
262     * Returns the Java type corresponding to the given method descriptor.
263     * Equivalent to <code>Type.getType(methodDescriptor)</code>.
264     *
265     * @param methodDescriptor
266     *            a method descriptor.
267     * @return the Java type corresponding to the given method descriptor.
268     */
269    public static Type getMethodType(final String methodDescriptor) {
270        return getType(methodDescriptor.toCharArray(), 0);
271    }
272
273    /**
274     * Returns the Java method type corresponding to the given argument and
275     * return types.
276     *
277     * @param returnType
278     *            the return type of the method.
279     * @param argumentTypes
280     *            the argument types of the method.
281     * @return the Java type corresponding to the given argument and return
282     *         types.
283     */
284    public static Type getMethodType(final Type returnType,
285            final Type... argumentTypes) {
286        return getType(getMethodDescriptor(returnType, argumentTypes));
287    }
288
289    /**
290     * Returns the Java type corresponding to the given class.
291     *
292     * @param c
293     *            a class.
294     * @return the Java type corresponding to the given class.
295     */
296    public static Type getType(final Class<?> c) {
297        if (c.isPrimitive()) {
298            if (c == Integer.TYPE) {
299                return INT_TYPE;
300            } else if (c == Void.TYPE) {
301                return VOID_TYPE;
302            } else if (c == Boolean.TYPE) {
303                return BOOLEAN_TYPE;
304            } else if (c == Byte.TYPE) {
305                return BYTE_TYPE;
306            } else if (c == Character.TYPE) {
307                return CHAR_TYPE;
308            } else if (c == Short.TYPE) {
309                return SHORT_TYPE;
310            } else if (c == Double.TYPE) {
311                return DOUBLE_TYPE;
312            } else if (c == Float.TYPE) {
313                return FLOAT_TYPE;
314            } else /* if (c == Long.TYPE) */{
315                return LONG_TYPE;
316            }
317        } else {
318            return getType(getDescriptor(c));
319        }
320    }
321
322    /**
323     * Returns the Java method type corresponding to the given constructor.
324     *
325     * @param c
326     *            a {@link Constructor Constructor} object.
327     * @return the Java method type corresponding to the given constructor.
328     */
329    public static Type getType(final Constructor<?> c) {
330        return getType(getConstructorDescriptor(c));
331    }
332
333    /**
334     * Returns the Java method type corresponding to the given method.
335     *
336     * @param m
337     *            a {@link Method Method} object.
338     * @return the Java method type corresponding to the given method.
339     */
340    public static Type getType(final Method m) {
341        return getType(getMethodDescriptor(m));
342    }
343
344    /**
345     * Returns the Java types corresponding to the argument types of the given
346     * method descriptor.
347     *
348     * @param methodDescriptor
349     *            a method descriptor.
350     * @return the Java types corresponding to the argument types of the given
351     *         method descriptor.
352     */
353    public static Type[] getArgumentTypes(final String methodDescriptor) {
354        char[] buf = methodDescriptor.toCharArray();
355        int off = 1;
356        int size = 0;
357        while (true) {
358            char car = buf[off++];
359            if (car == ')') {
360                break;
361            } else if (car == 'L') {
362                while (buf[off++] != ';') {
363                }
364                ++size;
365            } else if (car != '[') {
366                ++size;
367            }
368        }
369        Type[] args = new Type[size];
370        off = 1;
371        size = 0;
372        while (buf[off] != ')') {
373            args[size] = getType(buf, off);
374            off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
375            size += 1;
376        }
377        return args;
378    }
379
380    /**
381     * Returns the Java types corresponding to the argument types of the given
382     * method.
383     *
384     * @param method
385     *            a method.
386     * @return the Java types corresponding to the argument types of the given
387     *         method.
388     */
389    public static Type[] getArgumentTypes(final Method method) {
390        Class<?>[] classes = method.getParameterTypes();
391        Type[] types = new Type[classes.length];
392        for (int i = classes.length - 1; i >= 0; --i) {
393            types[i] = getType(classes[i]);
394        }
395        return types;
396    }
397
398    /**
399     * Returns the Java type corresponding to the return type of the given
400     * method descriptor.
401     *
402     * @param methodDescriptor
403     *            a method descriptor.
404     * @return the Java type corresponding to the return type of the given
405     *         method descriptor.
406     */
407    public static Type getReturnType(final String methodDescriptor) {
408        char[] buf = methodDescriptor.toCharArray();
409        return getType(buf, methodDescriptor.indexOf(')') + 1);
410    }
411
412    /**
413     * Returns the Java type corresponding to the return type of the given
414     * method.
415     *
416     * @param method
417     *            a method.
418     * @return the Java type corresponding to the return type of the given
419     *         method.
420     */
421    public static Type getReturnType(final Method method) {
422        return getType(method.getReturnType());
423    }
424
425    /**
426     * Computes the size of the arguments and of the return value of a method.
427     *
428     * @param desc
429     *            the descriptor of a method.
430     * @return the size of the arguments of the method (plus one for the
431     *         implicit this argument), argSize, and the size of its return
432     *         value, retSize, packed into a single int i =
433     *         <tt>(argSize &lt;&lt; 2) | retSize</tt> (argSize is therefore equal to
434     *         <tt>i &gt;&gt; 2</tt>, and retSize to <tt>i &amp; 0x03</tt>).
435     */
436    public static int getArgumentsAndReturnSizes(final String desc) {
437        int n = 1;
438        int c = 1;
439        while (true) {
440            char car = desc.charAt(c++);
441            if (car == ')') {
442                car = desc.charAt(c);
443                return n << 2
444                        | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
445            } else if (car == 'L') {
446                while (desc.charAt(c++) != ';') {
447                }
448                n += 1;
449            } else if (car == '[') {
450                while ((car = desc.charAt(c)) == '[') {
451                    ++c;
452                }
453                if (car == 'D' || car == 'J') {
454                    n -= 1;
455                }
456            } else if (car == 'D' || car == 'J') {
457                n += 2;
458            } else {
459                n += 1;
460            }
461        }
462    }
463
464    /**
465     * Returns the Java type corresponding to the given type descriptor. For
466     * method descriptors, buf is supposed to contain nothing more than the
467     * descriptor itself.
468     *
469     * @param buf
470     *            a buffer containing a type descriptor.
471     * @param off
472     *            the offset of this descriptor in the previous buffer.
473     * @return the Java type corresponding to the given type descriptor.
474     */
475    private static Type getType(final char[] buf, final int off) {
476        int len;
477        switch (buf[off]) {
478        case 'V':
479            return VOID_TYPE;
480        case 'Z':
481            return BOOLEAN_TYPE;
482        case 'C':
483            return CHAR_TYPE;
484        case 'B':
485            return BYTE_TYPE;
486        case 'S':
487            return SHORT_TYPE;
488        case 'I':
489            return INT_TYPE;
490        case 'F':
491            return FLOAT_TYPE;
492        case 'J':
493            return LONG_TYPE;
494        case 'D':
495            return DOUBLE_TYPE;
496        case '[':
497            len = 1;
498            while (buf[off + len] == '[') {
499                ++len;
500            }
501            if (buf[off + len] == 'L') {
502                ++len;
503                while (buf[off + len] != ';') {
504                    ++len;
505                }
506            }
507            return new Type(ARRAY, buf, off, len + 1);
508        case 'L':
509            len = 1;
510            while (buf[off + len] != ';') {
511                ++len;
512            }
513            return new Type(OBJECT, buf, off + 1, len - 1);
514            // case '(':
515        default:
516            return new Type(METHOD, buf, off, buf.length - off);
517        }
518    }
519
520    // ------------------------------------------------------------------------
521    // Accessors
522    // ------------------------------------------------------------------------
523
524    /**
525     * Returns the sort of this Java type.
526     *
527     * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
528     *         {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
529     *         {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
530     *         {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
531     *         METHOD}.
532     */
533    public int getSort() {
534        return sort;
535    }
536
537    /**
538     * Returns the number of dimensions of this array type. This method should
539     * only be used for an array type.
540     *
541     * @return the number of dimensions of this array type.
542     */
543    public int getDimensions() {
544        int i = 1;
545        while (buf[off + i] == '[') {
546            ++i;
547        }
548        return i;
549    }
550
551    /**
552     * Returns the type of the elements of this array type. This method should
553     * only be used for an array type.
554     *
555     * @return Returns the type of the elements of this array type.
556     */
557    public Type getElementType() {
558        return getType(buf, off + getDimensions());
559    }
560
561    /**
562     * Returns the binary name of the class corresponding to this type. This
563     * method must not be used on method types.
564     *
565     * @return the binary name of the class corresponding to this type.
566     */
567    public String getClassName() {
568        switch (sort) {
569        case VOID:
570            return "void";
571        case BOOLEAN:
572            return "boolean";
573        case CHAR:
574            return "char";
575        case BYTE:
576            return "byte";
577        case SHORT:
578            return "short";
579        case INT:
580            return "int";
581        case FLOAT:
582            return "float";
583        case LONG:
584            return "long";
585        case DOUBLE:
586            return "double";
587        case ARRAY:
588            StringBuilder sb = new StringBuilder(getElementType().getClassName());
589            for (int i = getDimensions(); i > 0; --i) {
590                sb.append("[]");
591            }
592            return sb.toString();
593        case OBJECT:
594            return new String(buf, off, len).replace('/', '.');
595        default:
596            return null;
597        }
598    }
599
600    /**
601     * Returns the internal name of the class corresponding to this object or
602     * array type. The internal name of a class is its fully qualified name (as
603     * returned by Class.getName(), where '.' are replaced by '/'. This method
604     * should only be used for an object or array type.
605     *
606     * @return the internal name of the class corresponding to this object type.
607     */
608    public String getInternalName() {
609        return new String(buf, off, len);
610    }
611
612    /**
613     * Returns the argument types of methods of this type. This method should
614     * only be used for method types.
615     *
616     * @return the argument types of methods of this type.
617     */
618    public Type[] getArgumentTypes() {
619        return getArgumentTypes(getDescriptor());
620    }
621
622    /**
623     * Returns the return type of methods of this type. This method should only
624     * be used for method types.
625     *
626     * @return the return type of methods of this type.
627     */
628    public Type getReturnType() {
629        return getReturnType(getDescriptor());
630    }
631
632    /**
633     * Returns the size of the arguments and of the return value of methods of
634     * this type. This method should only be used for method types.
635     *
636     * @return the size of the arguments (plus one for the implicit this
637     *         argument), argSize, and the size of the return value, retSize,
638     *         packed into a single
639     *         int i = <tt>(argSize &lt;&lt; 2) | retSize</tt>
640     *         (argSize is therefore equal to <tt>i &gt;&gt; 2</tt>,
641     *         and retSize to <tt>i &amp; 0x03</tt>).
642     */
643    public int getArgumentsAndReturnSizes() {
644        return getArgumentsAndReturnSizes(getDescriptor());
645    }
646
647    // ------------------------------------------------------------------------
648    // Conversion to type descriptors
649    // ------------------------------------------------------------------------
650
651    /**
652     * Returns the descriptor corresponding to this Java type.
653     *
654     * @return the descriptor corresponding to this Java type.
655     */
656    public String getDescriptor() {
657        StringBuilder buf = new StringBuilder();
658        getDescriptor(buf);
659        return buf.toString();
660    }
661
662    /**
663     * Returns the descriptor corresponding to the given argument and return
664     * types.
665     *
666     * @param returnType
667     *            the return type of the method.
668     * @param argumentTypes
669     *            the argument types of the method.
670     * @return the descriptor corresponding to the given argument and return
671     *         types.
672     */
673    public static String getMethodDescriptor(final Type returnType,
674            final Type... argumentTypes) {
675        StringBuilder buf = new StringBuilder();
676        buf.append('(');
677        for (int i = 0; i < argumentTypes.length; ++i) {
678            argumentTypes[i].getDescriptor(buf);
679        }
680        buf.append(')');
681        returnType.getDescriptor(buf);
682        return buf.toString();
683    }
684
685    /**
686     * Appends the descriptor corresponding to this Java type to the given
687     * string buffer.
688     *
689     * @param buf
690     *            the string buffer to which the descriptor must be appended.
691     */
692    private void getDescriptor(final StringBuilder buf) {
693        if (this.buf == null) {
694            // descriptor is in byte 3 of 'off' for primitive types (buf ==
695            // null)
696            buf.append((char) ((off & 0xFF000000) >>> 24));
697        } else if (sort == OBJECT) {
698            buf.append('L');
699            buf.append(this.buf, off, len);
700            buf.append(';');
701        } else { // sort == ARRAY || sort == METHOD
702            buf.append(this.buf, off, len);
703        }
704    }
705
706    // ------------------------------------------------------------------------
707    // Direct conversion from classes to type descriptors,
708    // without intermediate Type objects
709    // ------------------------------------------------------------------------
710
711    /**
712     * Returns the internal name of the given class. The internal name of a
713     * class is its fully qualified name, as returned by Class.getName(), where
714     * '.' are replaced by '/'.
715     *
716     * @param c
717     *            an object or array class.
718     * @return the internal name of the given class.
719     */
720    public static String getInternalName(final Class<?> c) {
721        return c.getName().replace('.', '/');
722    }
723
724    /**
725     * Returns the descriptor corresponding to the given Java type.
726     *
727     * @param c
728     *            an object class, a primitive class or an array class.
729     * @return the descriptor corresponding to the given class.
730     */
731    public static String getDescriptor(final Class<?> c) {
732        StringBuilder buf = new StringBuilder();
733        getDescriptor(buf, c);
734        return buf.toString();
735    }
736
737    /**
738     * Returns the descriptor corresponding to the given constructor.
739     *
740     * @param c
741     *            a {@link Constructor Constructor} object.
742     * @return the descriptor of the given constructor.
743     */
744    public static String getConstructorDescriptor(final Constructor<?> c) {
745        Class<?>[] parameters = c.getParameterTypes();
746        StringBuilder buf = new StringBuilder();
747        buf.append('(');
748        for (int i = 0; i < parameters.length; ++i) {
749            getDescriptor(buf, parameters[i]);
750        }
751        return buf.append(")V").toString();
752    }
753
754    /**
755     * Returns the descriptor corresponding to the given method.
756     *
757     * @param m
758     *            a {@link Method Method} object.
759     * @return the descriptor of the given method.
760     */
761    public static String getMethodDescriptor(final Method m) {
762        Class<?>[] parameters = m.getParameterTypes();
763        StringBuilder buf = new StringBuilder();
764        buf.append('(');
765        for (int i = 0; i < parameters.length; ++i) {
766            getDescriptor(buf, parameters[i]);
767        }
768        buf.append(')');
769        getDescriptor(buf, m.getReturnType());
770        return buf.toString();
771    }
772
773    /**
774     * Appends the descriptor of the given class to the given string buffer.
775     *
776     * @param buf
777     *            the string buffer to which the descriptor must be appended.
778     * @param c
779     *            the class whose descriptor must be computed.
780     */
781    private static void getDescriptor(final StringBuilder buf, final Class<?> c) {
782        Class<?> d = c;
783        while (true) {
784            if (d.isPrimitive()) {
785                char car;
786                if (d == Integer.TYPE) {
787                    car = 'I';
788                } else if (d == Void.TYPE) {
789                    car = 'V';
790                } else if (d == Boolean.TYPE) {
791                    car = 'Z';
792                } else if (d == Byte.TYPE) {
793                    car = 'B';
794                } else if (d == Character.TYPE) {
795                    car = 'C';
796                } else if (d == Short.TYPE) {
797                    car = 'S';
798                } else if (d == Double.TYPE) {
799                    car = 'D';
800                } else if (d == Float.TYPE) {
801                    car = 'F';
802                } else /* if (d == Long.TYPE) */{
803                    car = 'J';
804                }
805                buf.append(car);
806                return;
807            } else if (d.isArray()) {
808                buf.append('[');
809                d = d.getComponentType();
810            } else {
811                buf.append('L');
812                String name = d.getName();
813                int len = name.length();
814                for (int i = 0; i < len; ++i) {
815                    char car = name.charAt(i);
816                    buf.append(car == '.' ? '/' : car);
817                }
818                buf.append(';');
819                return;
820            }
821        }
822    }
823
824    // ------------------------------------------------------------------------
825    // Corresponding size and opcodes
826    // ------------------------------------------------------------------------
827
828    /**
829     * Returns the size of values of this type. This method must not be used for
830     * method types.
831     *
832     * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
833     *         <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
834     */
835    public int getSize() {
836        // the size is in byte 0 of 'off' for primitive types (buf == null)
837        return buf == null ? (off & 0xFF) : 1;
838    }
839
840    /**
841     * Returns a JVM instruction opcode adapted to this Java type. This method
842     * must not be used for method types.
843     *
844     * @param opcode
845     *            a JVM instruction opcode. This opcode must be one of ILOAD,
846     *            ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
847     *            ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
848     * @return an opcode that is similar to the given opcode, but adapted to
849     *         this Java type. For example, if this type is <tt>float</tt> and
850     *         <tt>opcode</tt> is IRETURN, this method returns FRETURN.
851     */
852    public int getOpcode(final int opcode) {
853        if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
854            // the offset for IALOAD or IASTORE is in byte 1 of 'off' for
855            // primitive types (buf == null)
856            return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
857        } else {
858            // the offset for other instructions is in byte 2 of 'off' for
859            // primitive types (buf == null)
860            return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
861        }
862    }
863
864    // ------------------------------------------------------------------------
865    // Equals, hashCode and toString
866    // ------------------------------------------------------------------------
867
868    /**
869     * Tests if the given object is equal to this type.
870     *
871     * @param o
872     *            the object to be compared to this type.
873     * @return <tt>true</tt> if the given object is equal to this type.
874     */
875    @Override
876    public boolean equals(final Object o) {
877        if (this == o) {
878            return true;
879        }
880        if (!(o instanceof Type)) {
881            return false;
882        }
883        Type t = (Type) o;
884        if (sort != t.sort) {
885            return false;
886        }
887        if (sort >= ARRAY) {
888            if (len != t.len) {
889                return false;
890            }
891            for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
892                if (buf[i] != t.buf[j]) {
893                    return false;
894                }
895            }
896        }
897        return true;
898    }
899
900    /**
901     * Returns a hash code value for this type.
902     *
903     * @return a hash code value for this type.
904     */
905    @Override
906    public int hashCode() {
907        int hc = 13 * sort;
908        if (sort >= ARRAY) {
909            for (int i = off, end = i + len; i < end; i++) {
910                hc = 17 * (hc + buf[i]);
911            }
912        }
913        return hc;
914    }
915
916    /**
917     * Returns a string representation of this type.
918     *
919     * @return the descriptor of this type.
920     */
921    @Override
922    public String toString() {
923        return getDescriptor();
924    }
925}
926