KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > asm > Type


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 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  * Contact: Eric.Bruneton@rd.francetelecom.com
31  *
32  * Author: Eric Bruneton
33  * with contributions from: Chris Nokleberg
34  */

35
36 package org.logicalcobwebs.asm;
37
38 import java.lang.reflect.Method JavaDoc;
39
40 /**
41  * A Java type. This class can be used to make it easier to manipulate type
42  * and method descriptors.
43  */

44
45 public class Type {
46
47   /**
48    * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
49    */

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

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

62
63   public final static int CHAR = 2;
64
65   /**
66    * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
67    */

68
69   public final static int BYTE = 3;
70
71   /**
72    * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
73    */

74
75   public final static int SHORT = 4;
76
77   /**
78    * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
79    */

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

86
87   public final static int FLOAT = 6;
88
89   /**
90    * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
91    */

92
93   public final static int LONG = 7;
94
95   /**
96    * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
97    */

98
99   public final static int DOUBLE = 8;
100
101   /**
102    * The sort of array reference types. See {@link #getSort getSort}.
103    */

104
105   public final static int ARRAY = 9;
106
107   /**
108    * The sort of object reference type. See {@link #getSort getSort}.
109    */

110
111   public final static int OBJECT = 10;
112
113   /**
114    * The <tt>void</tt> type.
115    */

116
117   public final static Type VOID_TYPE = new Type(VOID);
118
119   /**
120    * The <tt>boolean</tt> type.
121    */

122
123   public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
124
125   /**
126    * The <tt>char</tt> type.
127    */

128
129   public final static Type CHAR_TYPE = new Type(CHAR);
130
131   /**
132    * The <tt>byte</tt> type.
133    */

134
135   public final static Type BYTE_TYPE = new Type(BYTE);
136
137   /**
138    * The <tt>short</tt> type.
139    */

140
141   public final static Type SHORT_TYPE = new Type(SHORT);
142
143   /**
144    * The <tt>int</tt> type.
145    */

146
147   public final static Type INT_TYPE = new Type(INT);
148
149   /**
150    * The <tt>float</tt> type.
151    */

152
153   public final static Type FLOAT_TYPE = new Type(FLOAT);
154
155   /**
156    * The <tt>long</tt> type.
157    */

158
159   public final static Type LONG_TYPE = new Type(LONG);
160
161   /**
162    * The <tt>double</tt> type.
163    */

164
165   public final static Type DOUBLE_TYPE = new Type(DOUBLE);
166
167   // --------------------------------------------------------------------------
168
// Fields
169
// --------------------------------------------------------------------------
170

171   /**
172    * The sort of this Java type.
173    */

174
175   private final int sort;
176
177   /**
178    * A buffer containing the descriptor of this Java type.
179    * This field is only used for reference types.
180    */

181
182   private char[] buf;
183
184   /**
185    * The offset of the descriptor of this Java type in {@link #buf buf}.
186    * This field is only used for reference types.
187    */

188
189   private int off;
190
191   /**
192    * The length of the descriptor of this Java type.
193    */

194
195   private int len;
196
197   // --------------------------------------------------------------------------
198
// Constructors
199
// --------------------------------------------------------------------------
200

201   /**
202    * Constructs a primitive type.
203    *
204    * @param sort the sort of the primitive type to be constructed.
205    */

206
207   private Type (final int sort) {
208     this.sort = sort;
209     this.len = 1;
210   }
211
212   /**
213    * Constructs a reference type.
214    *
215    * @param sort the sort of the reference type to be constructed.
216    * @param buf a buffer containing the descriptor of the previous type.
217    * @param off the offset of this descriptor in the previous buffer.
218    * @param len the length of this descriptor.
219    */

220
221   private Type (
222     final int sort,
223     final char[] buf,
224     final int off,
225     final int len)
226   {
227     this.sort = sort;
228     this.buf = buf;
229     this.off = off;
230     this.len = len;
231   }
232
233   /**
234    * Returns the Java type corresponding to the given type descriptor.
235    *
236    * @param typeDescriptor a type descriptor.
237    * @return the Java type corresponding to the given type descriptor.
238    */

239
240   public static Type getType (final String JavaDoc typeDescriptor) {
241     return getType(typeDescriptor.toCharArray(), 0);
242   }
243
244   /**
245    * Returns the Java type corresponding to the given class.
246    *
247    * @param c a class.
248    * @return the Java type corresponding to the given class.
249    */

250
251   public static Type getType (final Class JavaDoc c) {
252     if (c.isPrimitive()) {
253       if (c == Integer.TYPE) {
254         return INT_TYPE;
255       } else if (c == Void.TYPE) {
256         return VOID_TYPE;
257       } else if (c == Boolean.TYPE) {
258         return BOOLEAN_TYPE;
259       } else if (c == Byte.TYPE) {
260         return BYTE_TYPE;
261       } else if (c == Character.TYPE) {
262         return CHAR_TYPE;
263       } else if (c == Short.TYPE) {
264         return SHORT_TYPE;
265       } else if (c == Double.TYPE) {
266         return DOUBLE_TYPE;
267       } else if (c == Float.TYPE) {
268         return FLOAT_TYPE;
269       } else /*if (c == Long.TYPE)*/ {
270         return LONG_TYPE;
271       }
272     } else {
273       return getType(getDescriptor(c));
274     }
275   }
276
277   /**
278    * Returns the Java types corresponding to the argument types of the given
279    * method descriptor.
280    *
281    * @param methodDescriptor a method descriptor.
282    * @return the Java types corresponding to the argument types of the given
283    * method descriptor.
284    */

285
286   public static Type[] getArgumentTypes (final String JavaDoc methodDescriptor) {
287     char[] buf = methodDescriptor.toCharArray();
288     int off = 1;
289     int size = 0;
290     while (true) {
291       char car = buf[off++];
292       if (car == ')') {
293         break;
294       } else if (car == 'L') {
295         while (buf[off++] != ';') {
296         }
297         ++size;
298       } else if (car != '[') {
299         ++size;
300       }
301     }
302     Type[] args = new Type[size];
303     off = 1;
304     size = 0;
305     while (buf[off] != ')') {
306       args[size] = getType(buf, off);
307       off += args[size].len;
308       size += 1;
309     }
310     return args;
311   }
312
313   /**
314    * Returns the Java types corresponding to the argument types of the given
315    * method.
316    *
317    * @param method a method.
318    * @return the Java types corresponding to the argument types of the given
319    * method.
320    */

321
322   public static Type[] getArgumentTypes (final Method JavaDoc method) {
323     Class JavaDoc[] classes = method.getParameterTypes();
324     Type[] types = new Type[classes.length];
325     for (int i = classes.length - 1; i >= 0; --i) {
326       types[i] = getType(classes[i]);
327     }
328     return types;
329   }
330
331   /**
332    * Returns the Java type corresponding to the return type of the given
333    * method descriptor.
334    *
335    * @param methodDescriptor a method descriptor.
336    * @return the Java type corresponding to the return type of the given
337    * method descriptor.
338    */

339
340   public static Type getReturnType (final String JavaDoc methodDescriptor) {
341     char[] buf = methodDescriptor.toCharArray();
342     return getType(buf, methodDescriptor.indexOf(')') + 1);
343   }
344
345   /**
346    * Returns the Java type corresponding to the return type of the given
347    * method.
348    *
349    * @param method a method.
350    * @return the Java type corresponding to the return type of the given
351    * method.
352    */

353
354   public static Type getReturnType (final Method JavaDoc method) {
355     return getType(method.getReturnType());
356   }
357
358   /**
359    * Returns the Java type corresponding to the given type descriptor.
360    *
361    * @param buf a buffer containing a type descriptor.
362    * @param off the offset of this descriptor in the previous buffer.
363    * @return the Java type corresponding to the given type descriptor.
364    */

365
366   private static Type getType (final char[] buf, final int off) {
367     int len;
368     switch (buf[off]) {
369       case 'V': return VOID_TYPE;
370       case 'Z': return BOOLEAN_TYPE;
371       case 'C': return CHAR_TYPE;
372       case 'B': return BYTE_TYPE;
373       case 'S': return SHORT_TYPE;
374       case 'I': return INT_TYPE;
375       case 'F': return FLOAT_TYPE;
376       case 'J': return LONG_TYPE;
377       case 'D': return DOUBLE_TYPE;
378       case '[':
379         len = 1;
380         while (buf[off + len] == '[') {
381           ++len;
382         }
383         if (buf[off + len] == 'L') {
384           ++len;
385           while (buf[off + len] != ';') {
386             ++len;
387           }
388         }
389         return new Type(ARRAY, buf, off, len + 1);
390       //case 'L':
391
default:
392         len = 1;
393         while (buf[off + len] != ';') {
394           ++len;
395         }
396         return new Type(OBJECT, buf, off, len + 1);
397     }
398   }
399
400   // --------------------------------------------------------------------------
401
// Accessors
402
// --------------------------------------------------------------------------
403

404   /**
405    * Returns the sort of this Java type.
406    *
407    * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
408    * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT}, {@link
409    * #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link
410    * #ARRAY ARRAY} or {@link #OBJECT OBJECT}.
411    */

412
413   public int getSort () {
414     return sort;
415   }
416
417   /**
418    * Returns the number of dimensions of this array type.
419    * This method should only be used for an array type.
420    *
421    * @return the number of dimensions of this array type.
422    */

423
424   public int getDimensions () {
425     int i = 1;
426     while (buf[off + i] == '[') {
427       ++i;
428     }
429     return i;
430   }
431
432   /**
433    * Returns the type of the elements of this array type.
434    * This method should only be used for an array type.
435    *
436    * @return Returns the type of the elements of this array type.
437    */

438
439   public Type getElementType () {
440     return getType(buf, off + getDimensions());
441   }
442
443   /**
444    * Returns the name of the class corresponding to this object type.
445    * This method should only be used for an object type.
446    *
447    * @return the fully qualified name of the class corresponding to this object
448    * type.
449    */

450
451   public String JavaDoc getClassName () {
452     return new String JavaDoc(buf, off + 1, len - 2).replace('/', '.');
453   }
454
455   /**
456    * Returns the internal name of the class corresponding to this object type.
457    * The internal name of a class is its fully qualified name, where '.' are
458    * replaced by '/'. * This method should only be used for an object type.
459    *
460    * @return the internal name of the class corresponding to this object type.
461    */

462
463   public String JavaDoc getInternalName () {
464     return new String JavaDoc(buf, off + 1, len - 2);
465   }
466
467   // --------------------------------------------------------------------------
468
// Conversion to type descriptors
469
// --------------------------------------------------------------------------
470

471   /**
472    * Returns the descriptor corresponding to this Java type.
473    *
474    * @return the descriptor corresponding to this Java type.
475    */

476
477   public String JavaDoc getDescriptor () {
478     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
479     getDescriptor(buf);
480     return buf.toString();
481   }
482
483   /**
484    * Returns the descriptor corresponding to the given argument and return
485    * types.
486    *
487    * @param returnType the return type of the method.
488    * @param argumentTypes the argument types of the method.
489    * @return the descriptor corresponding to the given argument and return
490    * types.
491    */

492
493   public static String JavaDoc getMethodDescriptor (
494     final Type returnType,
495     final Type[] argumentTypes)
496   {
497     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
498     buf.append('(');
499     for (int i = 0; i < argumentTypes.length; ++i) {
500       argumentTypes[i].getDescriptor(buf);
501     }
502     buf.append(')');
503     returnType.getDescriptor(buf);
504     return buf.toString();
505   }
506
507   /**
508    * Appends the descriptor corresponding to this Java type to the given string
509    * buffer.
510    *
511    * @param buf the string buffer to which the descriptor must be appended.
512    */

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

536   /**
537    * Returns the internal name of the given class. The internal name of a class
538    * is its fully qualified name, where '.' are replaced by '/'.
539    *
540    * @param c an object class.
541    * @return the internal name of the given class.
542    */

543
544   public static String JavaDoc getInternalName (final Class JavaDoc c) {
545     return c.getName().replace('.', '/');
546   }
547
548   /**
549    * Returns the descriptor corresponding to the given Java type.
550    *
551    * @param c an object class, a primitive class or an array class.
552    * @return the descriptor corresponding to the given class.
553    */

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

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

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

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

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

655
656   public int getOpcode (final int opcode) {
657     if (opcode == Constants.IALOAD || opcode == Constants.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 and hashcode
705
// --------------------------------------------------------------------------
706

707   public boolean equals (Object JavaDoc o) {
708     if (this == o) {
709       return true;
710     }
711     if (o == null || !(o instanceof Type)) {
712       return false;
713     }
714     Type t = (Type)o;
715     if (sort != t.sort) {
716       return false;
717     }
718     if (sort == Type.OBJECT || sort == Type.ARRAY) {
719       if (len != t.len) {
720         return false;
721       }
722       for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
723         if (buf[i] != t.buf[j]) {
724           return false;
725         }
726       }
727     }
728     return true;
729   }
730
731   public int hashCode () {
732     int hc = 13 * sort;
733     if (sort == Type.OBJECT || sort == Type.ARRAY) {
734       for (int i = off, end = i + len; i < end; i++) {
735         hc = 17 * (hc + buf[i]);
736       }
737     }
738     return hc;
739   }
740 }
741
Popular Tags