KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > asm > Type


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 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.tc.asm;
31
32 import java.lang.reflect.Method JavaDoc;
33
34 /**
35  * A Java type. This class can be used to make it easier to manipulate type and
36  * method descriptors.
37  *
38  * @author Eric Bruneton
39  * @author Chris Nokleberg
40  */

41 public class Type {
42
43     /**
44      * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
45      */

46     public final static int VOID = 0;
47
48     /**
49      * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
50      */

51     public final static int BOOLEAN = 1;
52
53     /**
54      * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
55      */

56     public final static int CHAR = 2;
57
58     /**
59      * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
60      */

61     public final static int BYTE = 3;
62
63     /**
64      * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
65      */

66     public final static int SHORT = 4;
67
68     /**
69      * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
70      */

71     public final static int INT = 5;
72
73     /**
74      * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
75      */

76     public final static int FLOAT = 6;
77
78     /**
79      * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
80      */

81     public final static int LONG = 7;
82
83     /**
84      * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
85      */

86     public final static int DOUBLE = 8;
87
88     /**
89      * The sort of array reference types. See {@link #getSort getSort}.
90      */

91     public final static int ARRAY = 9;
92
93     /**
94      * The sort of object reference type. See {@link #getSort getSort}.
95      */

96     public final static int OBJECT = 10;
97
98     /**
99      * The <tt>void</tt> type.
100      */

101     public final static Type VOID_TYPE = new Type(VOID);
102
103     /**
104      * The <tt>boolean</tt> type.
105      */

106     public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
107
108     /**
109      * The <tt>char</tt> type.
110      */

111     public final static Type CHAR_TYPE = new Type(CHAR);
112
113     /**
114      * The <tt>byte</tt> type.
115      */

116     public final static Type BYTE_TYPE = new Type(BYTE);
117
118     /**
119      * The <tt>short</tt> type.
120      */

121     public final static Type SHORT_TYPE = new Type(SHORT);
122
123     /**
124      * The <tt>int</tt> type.
125      */

126     public final static Type INT_TYPE = new Type(INT);
127
128     /**
129      * The <tt>float</tt> type.
130      */

131     public final static Type FLOAT_TYPE = new Type(FLOAT);
132
133     /**
134      * The <tt>long</tt> type.
135      */

136     public final static Type LONG_TYPE = new Type(LONG);
137
138     /**
139      * The <tt>double</tt> type.
140      */

141     public final static Type DOUBLE_TYPE = new Type(DOUBLE);
142
143     // ------------------------------------------------------------------------
144
// Fields
145
// ------------------------------------------------------------------------
146

147     /**
148      * The sort of this Java type.
149      */

150     private final int sort;
151
152     /**
153      * A buffer containing the descriptor of this Java type. This field is only
154      * used for reference types.
155      */

156     private char[] buf;
157
158     /**
159      * The offset of the descriptor of this Java type in {@link #buf buf}. This
160      * field is only used for reference types.
161      */

162     private int off;
163
164     /**
165      * The length of the descriptor of this Java type.
166      */

167     private int len;
168
169     // ------------------------------------------------------------------------
170
// Constructors
171
// ------------------------------------------------------------------------
172

173     /**
174      * Constructs a primitive type.
175      *
176      * @param sort the sort of the primitive type to be constructed.
177      */

178     private Type(final int sort) {
179         this.sort = sort;
180         this.len = 1;
181     }
182
183     /**
184      * Constructs a reference type.
185      *
186      * @param sort the sort of the reference type to be constructed.
187      * @param buf a buffer containing the descriptor of the previous type.
188      * @param off the offset of this descriptor in the previous buffer.
189      * @param len the length of this descriptor.
190      */

191     private Type(final int sort, final char[] buf, final int off, final int len)
192     {
193         this.sort = sort;
194         this.buf = buf;
195         this.off = off;
196         this.len = len;
197     }
198
199     /**
200      * Returns the Java type corresponding to the given type descriptor.
201      *
202      * @param typeDescriptor a type descriptor.
203      * @return the Java type corresponding to the given type descriptor.
204      */

205     public static Type getType(final String JavaDoc typeDescriptor) {
206         return getType(typeDescriptor.toCharArray(), 0);
207     }
208
209     /**
210      * Returns the Java type corresponding to the given class.
211      *
212      * @param c a class.
213      * @return the Java type corresponding to the given class.
214      */

215     public static Type getType(final Class JavaDoc c) {
216         if (c.isPrimitive()) {
217             if (c == Integer.TYPE) {
218                 return INT_TYPE;
219             } else if (c == Void.TYPE) {
220                 return VOID_TYPE;
221             } else if (c == Boolean.TYPE) {
222                 return BOOLEAN_TYPE;
223             } else if (c == Byte.TYPE) {
224                 return BYTE_TYPE;
225             } else if (c == Character.TYPE) {
226                 return CHAR_TYPE;
227             } else if (c == Short.TYPE) {
228                 return SHORT_TYPE;
229             } else if (c == Double.TYPE) {
230                 return DOUBLE_TYPE;
231             } else if (c == Float.TYPE) {
232                 return FLOAT_TYPE;
233             } else /* if (c == Long.TYPE) */{
234                 return LONG_TYPE;
235             }
236         } else {
237             return getType(getDescriptor(c));
238         }
239     }
240
241     /**
242      * Returns the Java types corresponding to the argument types of the given
243      * method descriptor.
244      *
245      * @param methodDescriptor a method descriptor.
246      * @return the Java types corresponding to the argument types of the given
247      * method descriptor.
248      */

249     public static Type[] getArgumentTypes(final String JavaDoc methodDescriptor) {
250         char[] buf = methodDescriptor.toCharArray();
251         int off = 1;
252         int size = 0;
253         while (true) {
254             char car = buf[off++];
255             if (car == ')') {
256                 break;
257             } else if (car == 'L') {
258                 while (buf[off++] != ';') {
259                 }
260                 ++size;
261             } else if (car != '[') {
262                 ++size;
263             }
264         }
265         Type[] args = new Type[size];
266         off = 1;
267         size = 0;
268         while (buf[off] != ')') {
269             args[size] = getType(buf, off);
270             off += args[size].len;
271             size += 1;
272         }
273         return args;
274     }
275
276     /**
277      * Returns the Java types corresponding to the argument types of the given
278      * method.
279      *
280      * @param method a method.
281      * @return the Java types corresponding to the argument types of the given
282      * method.
283      */

284     public static Type[] getArgumentTypes(final Method JavaDoc method) {
285         Class JavaDoc[] classes = method.getParameterTypes();
286         Type[] types = new Type[classes.length];
287         for (int i = classes.length - 1; i >= 0; --i) {
288             types[i] = getType(classes[i]);
289         }
290         return types;
291     }
292
293     /**
294      * Returns the Java type corresponding to the return type of the given
295      * method descriptor.
296      *
297      * @param methodDescriptor a method descriptor.
298      * @return the Java type corresponding to the return type of the given
299      * method descriptor.
300      */

301     public static Type getReturnType(final String JavaDoc methodDescriptor) {
302         char[] buf = methodDescriptor.toCharArray();
303         return getType(buf, methodDescriptor.indexOf(')') + 1);
304     }
305
306     /**
307      * Returns the Java type corresponding to the return type of the given
308      * method.
309      *
310      * @param method a method.
311      * @return the Java type corresponding to the return type of the given
312      * method.
313      */

314     public static Type getReturnType(final Method JavaDoc method) {
315         return getType(method.getReturnType());
316     }
317
318     /**
319      * Returns the Java type corresponding to the given type descriptor.
320      *
321      * @param buf a buffer containing a type descriptor.
322      * @param off the offset of this descriptor in the previous buffer.
323      * @return the Java type corresponding to the given type descriptor.
324      */

325     private static Type getType(final char[] buf, final int off) {
326         int len;
327         switch (buf[off]) {
328             case 'V':
329                 return VOID_TYPE;
330             case 'Z':
331                 return BOOLEAN_TYPE;
332             case 'C':
333                 return CHAR_TYPE;
334             case 'B':
335                 return BYTE_TYPE;
336             case 'S':
337                 return SHORT_TYPE;
338             case 'I':
339                 return INT_TYPE;
340             case 'F':
341                 return FLOAT_TYPE;
342             case 'J':
343                 return LONG_TYPE;
344             case 'D':
345                 return DOUBLE_TYPE;
346             case '[':
347                 len = 1;
348                 while (buf[off + len] == '[') {
349                     ++len;
350                 }
351                 if (buf[off + len] == 'L') {
352                     ++len;
353                     while (buf[off + len] != ';') {
354                         ++len;
355                     }
356                 }
357                 return new Type(ARRAY, buf, off, len + 1);
358             // case 'L':
359
default:
360                 len = 1;
361                 while (buf[off + len] != ';') {
362                     ++len;
363                 }
364                 return new Type(OBJECT, buf, off, len + 1);
365         }
366     }
367
368     // ------------------------------------------------------------------------
369
// Accessors
370
// ------------------------------------------------------------------------
371

372     /**
373      * Returns the sort of this Java type.
374      *
375      * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
376      * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
377      * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
378      * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or
379      * {@link #OBJECT OBJECT}.
380      */

381     public int getSort() {
382         return sort;
383     }
384
385     /**
386      * Returns the number of dimensions of this array type. This method should
387      * only be used for an array type.
388      *
389      * @return the number of dimensions of this array type.
390      */

391     public int getDimensions() {
392         int i = 1;
393         while (buf[off + i] == '[') {
394             ++i;
395         }
396         return i;
397     }
398
399     /**
400      * Returns the type of the elements of this array type. This method should
401      * only be used for an array type.
402      *
403      * @return Returns the type of the elements of this array type.
404      */

405     public Type getElementType() {
406         return getType(buf, off + getDimensions());
407     }
408
409     /**
410      * Returns the name of the class corresponding to this type.
411      *
412      * @return the fully qualified name of the class corresponding to this type.
413      */

414     public String JavaDoc getClassName() {
415         switch (sort) {
416             case VOID:
417                 return "void";
418             case BOOLEAN:
419                 return "boolean";
420             case CHAR:
421                 return "char";
422             case BYTE:
423                 return "byte";
424             case SHORT:
425                 return "short";
426             case INT:
427                 return "int";
428             case FLOAT:
429                 return "float";
430             case LONG:
431                 return "long";
432             case DOUBLE:
433                 return "double";
434             case ARRAY:
435                 StringBuffer JavaDoc b = new StringBuffer JavaDoc(getElementType().getClassName());
436                 for (int i = getDimensions(); i > 0; --i) {
437                     b.append("[]");
438                 }
439                 return b.toString();
440             // case OBJECT:
441
default:
442                 return new String JavaDoc(buf, off + 1, len - 2).replace('/', '.');
443         }
444     }
445
446     /**
447      * Returns the internal name of the class corresponding to this object type.
448      * The internal name of a class is its fully qualified name, where '.' are
449      * replaced by '/'. This method should only be used for an object type.
450      *
451      * @return the internal name of the class corresponding to this object type.
452      */

453     public String JavaDoc getInternalName() {
454         return new String JavaDoc(buf, off + 1, len - 2);
455     }
456
457     // ------------------------------------------------------------------------
458
// Conversion to type descriptors
459
// ------------------------------------------------------------------------
460

461     /**
462      * Returns the descriptor corresponding to this Java type.
463      *
464      * @return the descriptor corresponding to this Java type.
465      */

466     public String JavaDoc getDescriptor() {
467         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
468         getDescriptor(buf);
469         return buf.toString();
470     }
471
472     /**
473      * Returns the descriptor corresponding to the given argument and return
474      * types.
475      *
476      * @param returnType the return type of the method.
477      * @param argumentTypes the argument types of the method.
478      * @return the descriptor corresponding to the given argument and return
479      * types.
480      */

481     public static String JavaDoc getMethodDescriptor(
482         final Type returnType,
483         final Type[] argumentTypes)
484     {
485         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
486         buf.append('(');
487         for (int i = 0; i < argumentTypes.length; ++i) {
488             argumentTypes[i].getDescriptor(buf);
489         }
490         buf.append(')');
491         returnType.getDescriptor(buf);
492         return buf.toString();
493     }
494
495     /**
496      * Appends the descriptor corresponding to this Java type to the given
497      * string buffer.
498      *
499      * @param buf the string buffer to which the descriptor must be appended.
500      */

501     private void getDescriptor(final StringBuffer JavaDoc buf) {
502         switch (sort) {
503             case VOID:
504                 buf.append('V');
505                 return;
506             case BOOLEAN:
507                 buf.append('Z');
508                 return;
509             case CHAR:
510                 buf.append('C');
511                 return;
512             case BYTE:
513                 buf.append('B');
514                 return;
515             case SHORT:
516                 buf.append('S');
517                 return;
518             case INT:
519                 buf.append('I');
520                 return;
521             case FLOAT:
522                 buf.append('F');
523                 return;
524             case LONG:
525                 buf.append('J');
526                 return;
527             case DOUBLE:
528                 buf.append('D');
529                 return;
530             // case ARRAY:
531
// case OBJECT:
532
default:
533                 buf.append(this.buf, off, len);
534         }
535     }
536
537     // ------------------------------------------------------------------------
538
// Direct conversion from classes to type descriptors,
539
// without intermediate Type objects
540
// ------------------------------------------------------------------------
541

542     /**
543      * Returns the internal name of the given class. The internal name of a
544      * class is its fully qualified name, where '.' are replaced by '/'.
545      *
546      * @param c an object class.
547      * @return the internal name of the given class.
548      */

549     public static String JavaDoc getInternalName(final Class JavaDoc c) {
550         return c.getName().replace('.', '/');
551     }
552
553     /**
554      * Returns the descriptor corresponding to the given Java type.
555      *
556      * @param c an object class, a primitive class or an array class.
557      * @return the descriptor corresponding to the given class.
558      */

559     public static String JavaDoc getDescriptor(final Class JavaDoc c) {
560         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
561         getDescriptor(buf, c);
562         return buf.toString();
563     }
564
565     /**
566      * Returns the descriptor corresponding to the given method.
567      *
568      * @param m a {@link Method Method} object.
569      * @return the descriptor of the given method.
570      */

571     public static String JavaDoc getMethodDescriptor(final Method JavaDoc m) {
572         Class JavaDoc[] parameters = m.getParameterTypes();
573         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
574         buf.append('(');
575         for (int i = 0; i < parameters.length; ++i) {
576             getDescriptor(buf, parameters[i]);
577         }
578         buf.append(')');
579         getDescriptor(buf, m.getReturnType());
580         return buf.toString();
581     }
582
583     /**
584      * Appends the descriptor of the given class to the given string buffer.
585      *
586      * @param buf the string buffer to which the descriptor must be appended.
587      * @param c the class whose descriptor must be computed.
588      */

589     private static void getDescriptor(final StringBuffer JavaDoc buf, final Class JavaDoc c) {
590         Class JavaDoc d = c;
591         while (true) {
592             if (d.isPrimitive()) {
593                 char car;
594                 if (d == Integer.TYPE) {
595                     car = 'I';
596                 } else if (d == Void.TYPE) {
597                     car = 'V';
598                 } else if (d == Boolean.TYPE) {
599                     car = 'Z';
600                 } else if (d == Byte.TYPE) {
601                     car = 'B';
602                 } else if (d == Character.TYPE) {
603                     car = 'C';
604                 } else if (d == Short.TYPE) {
605                     car = 'S';
606                 } else if (d == Double.TYPE) {
607                     car = 'D';
608                 } else if (d == Float.TYPE) {
609                     car = 'F';
610                 } else /* if (d == Long.TYPE) */{
611                     car = 'J';
612                 }
613                 buf.append(car);
614                 return;
615             } else if (d.isArray()) {
616                 buf.append('[');
617                 d = d.getComponentType();
618             } else {
619                 buf.append('L');
620                 String JavaDoc name = d.getName();
621                 int len = name.length();
622                 for (int i = 0; i < len; ++i) {
623                     char car = name.charAt(i);
624                     buf.append(car == '.' ? '/' : car);
625                 }
626                 buf.append(';');
627                 return;
628             }
629         }
630     }
631
632     // ------------------------------------------------------------------------
633
// Corresponding size and opcodes
634
// ------------------------------------------------------------------------
635

636     /**
637      * Returns the size of values of this type.
638      *
639      * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
640      * <tt>double</tt>, and 1 otherwise.
641      */

642     public int getSize() {
643         return (sort == LONG || sort == DOUBLE ? 2 : 1);
644     }
645
646     /**
647      * Returns a JVM instruction opcode adapted to this Java type.
648      *
649      * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
650      * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
651      * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
652      * @return an opcode that is similar to the given opcode, but adapted to
653      * this Java type. For example, if this type is <tt>float</tt> and
654      * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
655      */

656     public int getOpcode(final int opcode) {
657         if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
658             switch (sort) {
659                 case BOOLEAN:
660                 case BYTE:
661                     return opcode + 5;
662                 case CHAR:
663                     return opcode + 6;
664                 case SHORT:
665                     return opcode + 7;
666                 case INT:
667                     return opcode;
668                 case FLOAT:
669                     return opcode + 2;
670                 case LONG:
671                     return opcode + 1;
672                 case DOUBLE:
673                     return opcode + 3;
674                 // case ARRAY:
675
// case OBJECT:
676
default:
677                     return opcode + 4;
678             }
679         } else {
680             switch (sort) {
681                 case VOID:
682                     return opcode + 5;
683                 case BOOLEAN:
684                 case CHAR:
685                 case BYTE:
686                 case SHORT:
687                 case INT:
688                     return opcode;
689                 case FLOAT:
690                     return opcode + 2;
691                 case LONG:
692                     return opcode + 1;
693                 case DOUBLE:
694                     return opcode + 3;
695                 // case ARRAY:
696
// case OBJECT:
697
default:
698                     return opcode + 4;
699             }
700         }
701     }
702
703     // ------------------------------------------------------------------------
704
// Equals, hashCode and toString
705
// ------------------------------------------------------------------------
706

707     /**
708      * Tests if the given object is equal to this type.
709      *
710      * @param o the object to be compared to this type.
711      * @return <tt>true</tt> if the given object is equal to this type.
712      */

713     public boolean equals(final Object JavaDoc o) {
714         if (this == o) {
715             return true;
716         }
717         if (o == null || !(o instanceof Type)) {
718             return false;
719         }
720         Type t = (Type) o;
721         if (sort != t.sort) {
722             return false;
723         }
724         if (sort == Type.OBJECT || sort == Type.ARRAY) {
725             if (len != t.len) {
726                 return false;
727             }
728             for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
729                 if (buf[i] != t.buf[j]) {
730                     return false;
731                 }
732             }
733         }
734         return true;
735     }
736
737     /**
738      * Returns a hash code value for this type.
739      *
740      * @return a hash code value for this type.
741      */

742     public int hashCode() {
743         int hc = 13 * sort;
744         if (sort == Type.OBJECT || sort == Type.ARRAY) {
745             for (int i = off, end = i + len; i < end; i++) {
746                 hc = 17 * (hc + buf[i]);
747             }
748         }
749         return hc;
750     }
751
752     /**
753      * Returns a string representation of this type.
754      *
755      * @return the descriptor of this type.
756      */

757     public String JavaDoc toString() {
758         return getDescriptor();
759     }
760 }
761
Popular Tags