view src/clojure/asm/Type.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
line wrap: on
line source
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 clojure.asm;
32 import java.lang.reflect.Constructor;
33 import java.lang.reflect.Method;
35 /**
36 * A Java type. This class can be used to make it easier to manipulate type and
37 * method descriptors.
38 *
39 * @author Eric Bruneton
40 * @author Chris Nokleberg
41 */
42 public class Type{
44 /**
45 * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
46 */
47 public final static int VOID = 0;
49 /**
50 * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
51 */
52 public final static int BOOLEAN = 1;
54 /**
55 * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
56 */
57 public final static int CHAR = 2;
59 /**
60 * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
61 */
62 public final static int BYTE = 3;
64 /**
65 * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
66 */
67 public final static int SHORT = 4;
69 /**
70 * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
71 */
72 public final static int INT = 5;
74 /**
75 * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
76 */
77 public final static int FLOAT = 6;
79 /**
80 * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
81 */
82 public final static int LONG = 7;
84 /**
85 * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
86 */
87 public final static int DOUBLE = 8;
89 /**
90 * The sort of array reference types. See {@link #getSort getSort}.
91 */
92 public final static int ARRAY = 9;
94 /**
95 * The sort of object reference type. See {@link #getSort getSort}.
96 */
97 public final static int OBJECT = 10;
99 /**
100 * The <tt>void</tt> type.
101 */
102 public final static Type VOID_TYPE = new Type(VOID);
104 /**
105 * The <tt>boolean</tt> type.
106 */
107 public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
109 /**
110 * The <tt>char</tt> type.
111 */
112 public final static Type CHAR_TYPE = new Type(CHAR);
114 /**
115 * The <tt>byte</tt> type.
116 */
117 public final static Type BYTE_TYPE = new Type(BYTE);
119 /**
120 * The <tt>short</tt> type.
121 */
122 public final static Type SHORT_TYPE = new Type(SHORT);
124 /**
125 * The <tt>int</tt> type.
126 */
127 public final static Type INT_TYPE = new Type(INT);
129 /**
130 * The <tt>float</tt> type.
131 */
132 public final static Type FLOAT_TYPE = new Type(FLOAT);
134 /**
135 * The <tt>long</tt> type.
136 */
137 public final static Type LONG_TYPE = new Type(LONG);
139 /**
140 * The <tt>double</tt> type.
141 */
142 public final static Type DOUBLE_TYPE = new Type(DOUBLE);
144 // ------------------------------------------------------------------------
145 // Fields
146 // ------------------------------------------------------------------------
148 /**
149 * The sort of this Java type.
150 */
151 private final int sort;
153 /**
154 * A buffer containing the descriptor of this Java type. This field is only
155 * used for reference types.
156 */
157 private char[] buf;
159 /**
160 * The offset of the descriptor of this Java type in {@link #buf buf}. This
161 * field is only used for reference types.
162 */
163 private int off;
165 /**
166 * The length of the descriptor of this Java type.
167 */
168 private int len;
170 // ------------------------------------------------------------------------
171 // Constructors
172 // ------------------------------------------------------------------------
174 /**
175 * Constructs a primitive type.
176 *
177 * @param sort the sort of the primitive type to be constructed.
178 */
179 private Type(final int sort){
180 this.sort = sort;
181 this.len = 1;
182 }
184 /**
185 * Constructs a reference type.
186 *
187 * @param sort the sort of the reference type to be constructed.
188 * @param buf a buffer containing the descriptor of the previous type.
189 * @param off the offset of this descriptor in the previous buffer.
190 * @param len the length of this descriptor.
191 */
192 private Type(final int sort, final char[] buf, final int off, final int len){
193 this.sort = sort;
194 this.buf = buf;
195 this.off = off;
196 this.len = len;
197 }
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 typeDescriptor){
206 return getType(typeDescriptor.toCharArray(), 0);
207 }
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 c){
216 if(c.isPrimitive())
217 {
218 if(c == Integer.TYPE)
219 {
220 return INT_TYPE;
221 }
222 else if(c == Void.TYPE)
223 {
224 return VOID_TYPE;
225 }
226 else if(c == Boolean.TYPE)
227 {
228 return BOOLEAN_TYPE;
229 }
230 else if(c == Byte.TYPE)
231 {
232 return BYTE_TYPE;
233 }
234 else if(c == Character.TYPE)
235 {
236 return CHAR_TYPE;
237 }
238 else if(c == Short.TYPE)
239 {
240 return SHORT_TYPE;
241 }
242 else if(c == Double.TYPE)
243 {
244 return DOUBLE_TYPE;
245 }
246 else if(c == Float.TYPE)
247 {
248 return FLOAT_TYPE;
249 }
250 else /* if (c == Long.TYPE) */
251 {
252 return LONG_TYPE;
253 }
254 }
255 else
256 {
257 return getType(getDescriptor(c));
258 }
259 }
261 /**
262 * Returns the {@link Type#OBJECT} type for the given internal class name.
263 * This is a shortcut method for <code>Type.getType("L"+name+";")</code>.
264 * <i>Note that opposed to {@link Type#getType(String)}, this method takes
265 * internal class names and not class descriptor.</i>
266 *
267 * @param name an internal class name.
268 * @return the the {@link Type#OBJECT} type for the given class name.
269 */
270 public static Type getObjectType(String name){
271 int l = name.length();
272 char[] buf = new char[l + 2];
273 buf[0] = 'L';
274 buf[l + 1] = ';';
275 name.getChars(0, l, buf, 1);
276 return new Type(OBJECT, buf, 0, l + 2);
277 }
279 /**
280 * Returns the Java types corresponding to the argument types of the given
281 * method descriptor.
282 *
283 * @param methodDescriptor a method descriptor.
284 * @return the Java types corresponding to the argument types of the given
285 * method descriptor.
286 */
287 public static Type[] getArgumentTypes(final String methodDescriptor){
288 char[] buf = methodDescriptor.toCharArray();
289 int off = 1;
290 int size = 0;
291 while(true)
292 {
293 char car = buf[off++];
294 if(car == ')')
295 {
296 break;
297 }
298 else if(car == 'L')
299 {
300 while(buf[off++] != ';')
301 {
302 }
303 ++size;
304 }
305 else if(car != '[')
306 {
307 ++size;
308 }
309 }
310 Type[] args = new Type[size];
311 off = 1;
312 size = 0;
313 while(buf[off] != ')')
314 {
315 args[size] = getType(buf, off);
316 off += args[size].len;
317 size += 1;
318 }
319 return args;
320 }
322 /**
323 * Returns the Java types corresponding to the argument types of the given
324 * method.
325 *
326 * @param method a method.
327 * @return the Java types corresponding to the argument types of the given
328 * method.
329 */
330 public static Type[] getArgumentTypes(final Method method){
331 Class[] classes = method.getParameterTypes();
332 Type[] types = new Type[classes.length];
333 for(int i = classes.length - 1; i >= 0; --i)
334 {
335 types[i] = getType(classes[i]);
336 }
337 return types;
338 }
340 /**
341 * Returns the Java type corresponding to the return type of the given
342 * method descriptor.
343 *
344 * @param methodDescriptor a method descriptor.
345 * @return the Java type corresponding to the return type of the given
346 * method descriptor.
347 */
348 public static Type getReturnType(final String methodDescriptor){
349 char[] buf = methodDescriptor.toCharArray();
350 return getType(buf, methodDescriptor.indexOf(')') + 1);
351 }
353 /**
354 * Returns the Java type corresponding to the return type of the given
355 * method.
356 *
357 * @param method a method.
358 * @return the Java type corresponding to the return type of the given
359 * method.
360 */
361 public static Type getReturnType(final Method method){
362 return getType(method.getReturnType());
363 }
365 /**
366 * Returns the Java type corresponding to the given type descriptor.
367 *
368 * @param buf a buffer containing a type descriptor.
369 * @param off the offset of this descriptor in the previous buffer.
370 * @return the Java type corresponding to the given type descriptor.
371 */
372 private static Type getType(final char[] buf, final int off){
373 int len;
374 switch(buf[off])
375 {
376 case'V':
377 return VOID_TYPE;
378 case'Z':
379 return BOOLEAN_TYPE;
380 case'C':
381 return CHAR_TYPE;
382 case'B':
383 return BYTE_TYPE;
384 case'S':
385 return SHORT_TYPE;
386 case'I':
387 return INT_TYPE;
388 case'F':
389 return FLOAT_TYPE;
390 case'J':
391 return LONG_TYPE;
392 case'D':
393 return DOUBLE_TYPE;
394 case'[':
395 len = 1;
396 while(buf[off + len] == '[')
397 {
398 ++len;
399 }
400 if(buf[off + len] == 'L')
401 {
402 ++len;
403 while(buf[off + len] != ';')
404 {
405 ++len;
406 }
407 }
408 return new Type(ARRAY, buf, off, len + 1);
409 // case 'L':
410 default:
411 len = 1;
412 while(buf[off + len] != ';')
413 {
414 ++len;
415 }
416 return new Type(OBJECT, buf, off, len + 1);
417 }
418 }
420 // ------------------------------------------------------------------------
421 // Accessors
422 // ------------------------------------------------------------------------
424 /**
425 * Returns the sort of this Java type.
426 *
427 * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN},
428 * {@link #CHAR CHAR}, {@link #BYTE BYTE}, {@link #SHORT SHORT},
429 * {@link #INT INT}, {@link #FLOAT FLOAT}, {@link #LONG LONG},
430 * {@link #DOUBLE DOUBLE}, {@link #ARRAY ARRAY} or
431 * {@link #OBJECT OBJECT}.
432 */
433 public int getSort(){
434 return sort;
435 }
437 /**
438 * Returns the number of dimensions of this array type. This method should
439 * only be used for an array type.
440 *
441 * @return the number of dimensions of this array type.
442 */
443 public int getDimensions(){
444 int i = 1;
445 while(buf[off + i] == '[')
446 {
447 ++i;
448 }
449 return i;
450 }
452 /**
453 * Returns the type of the elements of this array type. This method should
454 * only be used for an array type.
455 *
456 * @return Returns the type of the elements of this array type.
457 */
458 public Type getElementType(){
459 return getType(buf, off + getDimensions());
460 }
462 /**
463 * Returns the name of the class corresponding to this type.
464 *
465 * @return the fully qualified name of the class corresponding to this type.
466 */
467 public String getClassName(){
468 switch(sort)
469 {
470 case VOID:
471 return "void";
472 case BOOLEAN:
473 return "boolean";
474 case CHAR:
475 return "char";
476 case BYTE:
477 return "byte";
478 case SHORT:
479 return "short";
480 case INT:
481 return "int";
482 case FLOAT:
483 return "float";
484 case LONG:
485 return "long";
486 case DOUBLE:
487 return "double";
488 case ARRAY:
489 StringBuffer b = new StringBuffer(getElementType().getClassName());
490 for(int i = getDimensions(); i > 0; --i)
491 {
492 b.append("[]");
493 }
494 return b.toString();
495 // case OBJECT:
496 default:
497 return new String(buf, off + 1, len - 2).replace('/', '.');
498 }
499 }
501 /**
502 * Returns the internal name of the class corresponding to this object type.
503 * The internal name of a class is its fully qualified name, where '.' are
504 * replaced by '/'. This method should only be used for an object type.
505 *
506 * @return the internal name of the class corresponding to this object type.
507 */
508 public String getInternalName(){
509 return new String(buf, off + 1, len - 2);
510 }
512 // ------------------------------------------------------------------------
513 // Conversion to type descriptors
514 // ------------------------------------------------------------------------
516 /**
517 * Returns the descriptor corresponding to this Java type.
518 *
519 * @return the descriptor corresponding to this Java type.
520 */
521 public String getDescriptor(){
522 StringBuffer buf = new StringBuffer();
523 getDescriptor(buf);
524 return buf.toString();
525 }
527 /**
528 * Returns the descriptor corresponding to the given argument and return
529 * types.
530 *
531 * @param returnType the return type of the method.
532 * @param argumentTypes the argument types of the method.
533 * @return the descriptor corresponding to the given argument and return
534 * types.
535 */
536 public static String getMethodDescriptor(
537 final Type returnType,
538 final Type[] argumentTypes){
539 StringBuffer buf = new StringBuffer();
540 buf.append('(');
541 for(int i = 0; i < argumentTypes.length; ++i)
542 {
543 argumentTypes[i].getDescriptor(buf);
544 }
545 buf.append(')');
546 returnType.getDescriptor(buf);
547 return buf.toString();
548 }
550 /**
551 * Appends the descriptor corresponding to this Java type to the given
552 * string buffer.
553 *
554 * @param buf the string buffer to which the descriptor must be appended.
555 */
556 private void getDescriptor(final StringBuffer buf){
557 switch(sort)
558 {
559 case VOID:
560 buf.append('V');
561 return;
562 case BOOLEAN:
563 buf.append('Z');
564 return;
565 case CHAR:
566 buf.append('C');
567 return;
568 case BYTE:
569 buf.append('B');
570 return;
571 case SHORT:
572 buf.append('S');
573 return;
574 case INT:
575 buf.append('I');
576 return;
577 case FLOAT:
578 buf.append('F');
579 return;
580 case LONG:
581 buf.append('J');
582 return;
583 case DOUBLE:
584 buf.append('D');
585 return;
586 // case ARRAY:
587 // case OBJECT:
588 default:
589 buf.append(this.buf, off, len);
590 }
591 }
593 // ------------------------------------------------------------------------
594 // Direct conversion from classes to type descriptors,
595 // without intermediate Type objects
596 // ------------------------------------------------------------------------
598 /**
599 * Returns the internal name of the given class. The internal name of a
600 * class is its fully qualified name, where '.' are replaced by '/'.
601 *
602 * @param c an object class.
603 * @return the internal name of the given class.
604 */
605 public static String getInternalName(final Class c){
606 return c.getName().replace('.', '/');
607 }
609 /**
610 * Returns the descriptor corresponding to the given Java type.
611 *
612 * @param c an object class, a primitive class or an array class.
613 * @return the descriptor corresponding to the given class.
614 */
615 public static String getDescriptor(final Class c){
616 StringBuffer buf = new StringBuffer();
617 getDescriptor(buf, c);
618 return buf.toString();
619 }
621 /**
622 * Returns the descriptor corresponding to the given constructor.
623 *
624 * @param c a {@link Constructor Constructor} object.
625 * @return the descriptor of the given constructor.
626 */
627 public static String getConstructorDescriptor(final Constructor c){
628 Class[] parameters = c.getParameterTypes();
629 StringBuffer buf = new StringBuffer();
630 buf.append('(');
631 for(int i = 0; i < parameters.length; ++i)
632 {
633 getDescriptor(buf, parameters[i]);
634 }
635 return buf.append(")V").toString();
636 }
638 /**
639 * Returns the descriptor corresponding to the given method.
640 *
641 * @param m a {@link Method Method} object.
642 * @return the descriptor of the given method.
643 */
644 public static String getMethodDescriptor(final Method m){
645 Class[] parameters = m.getParameterTypes();
646 StringBuffer buf = new StringBuffer();
647 buf.append('(');
648 for(int i = 0; i < parameters.length; ++i)
649 {
650 getDescriptor(buf, parameters[i]);
651 }
652 buf.append(')');
653 getDescriptor(buf, m.getReturnType());
654 return buf.toString();
655 }
657 /**
658 * Appends the descriptor of the given class to the given string buffer.
659 *
660 * @param buf the string buffer to which the descriptor must be appended.
661 * @param c the class whose descriptor must be computed.
662 */
663 private static void getDescriptor(final StringBuffer buf, final Class c){
664 Class d = c;
665 while(true)
666 {
667 if(d.isPrimitive())
668 {
669 char car;
670 if(d == Integer.TYPE)
671 {
672 car = 'I';
673 }
674 else if(d == Void.TYPE)
675 {
676 car = 'V';
677 }
678 else if(d == Boolean.TYPE)
679 {
680 car = 'Z';
681 }
682 else if(d == Byte.TYPE)
683 {
684 car = 'B';
685 }
686 else if(d == Character.TYPE)
687 {
688 car = 'C';
689 }
690 else if(d == Short.TYPE)
691 {
692 car = 'S';
693 }
694 else if(d == Double.TYPE)
695 {
696 car = 'D';
697 }
698 else if(d == Float.TYPE)
699 {
700 car = 'F';
701 }
702 else /* if (d == Long.TYPE) */
703 {
704 car = 'J';
705 }
706 buf.append(car);
707 return;
708 }
709 else if(d.isArray())
710 {
711 buf.append('[');
712 d = d.getComponentType();
713 }
714 else
715 {
716 buf.append('L');
717 String name = d.getName();
718 int len = name.length();
719 for(int i = 0; i < len; ++i)
720 {
721 char car = name.charAt(i);
722 buf.append(car == '.' ? '/' : car);
723 }
724 buf.append(';');
725 return;
726 }
727 }
728 }
730 // ------------------------------------------------------------------------
731 // Corresponding size and opcodes
732 // ------------------------------------------------------------------------
734 /**
735 * Returns the size of values of this type.
736 *
737 * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
738 * <tt>double</tt>, and 1 otherwise.
739 */
740 public int getSize(){
741 return sort == LONG || sort == DOUBLE ? 2 : 1;
742 }
744 /**
745 * Returns a JVM instruction opcode adapted to this Java type.
746 *
747 * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
748 * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
749 * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
750 * @return an opcode that is similar to the given opcode, but adapted to
751 * this Java type. For example, if this type is <tt>float</tt> and
752 * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
753 */
754 public int getOpcode(final int opcode){
755 if(opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE)
756 {
757 switch(sort)
758 {
759 case BOOLEAN:
760 case BYTE:
761 return opcode + 5;
762 case CHAR:
763 return opcode + 6;
764 case SHORT:
765 return opcode + 7;
766 case INT:
767 return opcode;
768 case FLOAT:
769 return opcode + 2;
770 case LONG:
771 return opcode + 1;
772 case DOUBLE:
773 return opcode + 3;
774 // case ARRAY:
775 // case OBJECT:
776 default:
777 return opcode + 4;
778 }
779 }
780 else
781 {
782 switch(sort)
783 {
784 case VOID:
785 return opcode + 5;
786 case BOOLEAN:
787 case CHAR:
788 case BYTE:
789 case SHORT:
790 case INT:
791 return opcode;
792 case FLOAT:
793 return opcode + 2;
794 case LONG:
795 return opcode + 1;
796 case DOUBLE:
797 return opcode + 3;
798 // case ARRAY:
799 // case OBJECT:
800 default:
801 return opcode + 4;
802 }
803 }
804 }
806 // ------------------------------------------------------------------------
807 // Equals, hashCode and toString
808 // ------------------------------------------------------------------------
810 /**
811 * Tests if the given object is equal to this type.
812 *
813 * @param o the object to be compared to this type.
814 * @return <tt>true</tt> if the given object is equal to this type.
815 */
816 public boolean equals(final Object o){
817 if(this == o)
818 {
819 return true;
820 }
821 if(!(o instanceof Type))
822 {
823 return false;
824 }
825 Type t = (Type) o;
826 if(sort != t.sort)
827 {
828 return false;
829 }
830 if(sort == Type.OBJECT || sort == Type.ARRAY)
831 {
832 if(len != t.len)
833 {
834 return false;
835 }
836 for(int i = off, j = t.off, end = i + len; i < end; i++, j++)
837 {
838 if(buf[i] != t.buf[j])
839 {
840 return false;
841 }
842 }
843 }
844 return true;
845 }
847 /**
848 * Returns a hash code value for this type.
849 *
850 * @return a hash code value for this type.
851 */
852 public int hashCode(){
853 int hc = 13 * sort;
854 if(sort == Type.OBJECT || sort == Type.ARRAY)
855 {
856 for(int i = off, end = i + len; i < end; i++)
857 {
858 hc = 17 * (hc + buf[i]);
859 }
860 }
861 return hc;
862 }
864 /**
865 * Returns a string representation of this type.
866 *
867 * @return the descriptor of this type.
868 */
869 public String toString(){
870 return getDescriptor();
871 }
872 }