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