Mercurial > lasercutter
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 framework3 * Copyright (c) 2000-2005 INRIA, France Telecom4 * All rights reserved.5 *6 * Redistribution and use in source and binary forms, with or without7 * modification, are permitted provided that the following conditions8 * are met:9 * 1. Redistributions of source code must retain the above copyright10 * notice, this list of conditions and the following disclaimer.11 * 2. Redistributions in binary form must reproduce the above copyright12 * notice, this list of conditions and the following disclaimer in the13 * documentation and/or other materials provided with the distribution.14 * 3. Neither the name of the copyright holders nor the names of its15 * contributors may be used to endorse or promote products derived from16 * 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, THE20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF28 * 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 and37 * method descriptors.38 *39 * @author Eric Bruneton40 * @author Chris Nokleberg41 */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 // Fields146 // ------------------------------------------------------------------------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 only155 * used for reference types.156 */157 private char[] buf;159 /**160 * The offset of the descriptor of this Java type in {@link #buf buf}. This161 * 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 // Constructors172 // ------------------------------------------------------------------------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 else256 {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 takes265 * 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 given281 * method descriptor.282 *283 * @param methodDescriptor a method descriptor.284 * @return the Java types corresponding to the argument types of the given285 * 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 given324 * method.325 *326 * @param method a method.327 * @return the Java types corresponding to the argument types of the given328 * 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 given342 * method descriptor.343 *344 * @param methodDescriptor a method descriptor.345 * @return the Java type corresponding to the return type of the given346 * 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 given355 * method.356 *357 * @param method a method.358 * @return the Java type corresponding to the return type of the given359 * 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 // Accessors422 // ------------------------------------------------------------------------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} or431 * {@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 should439 * 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 should454 * 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 '.' are504 * 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 descriptors514 // ------------------------------------------------------------------------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 return529 * 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 return534 * 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 given552 * 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 objects596 // ------------------------------------------------------------------------598 /**599 * Returns the internal name of the given class. The internal name of a600 * 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 else715 {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 opcodes732 // ------------------------------------------------------------------------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> and738 * <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 to751 * this Java type. For example, if this type is <tt>float</tt> and752 * <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 else781 {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 toString808 // ------------------------------------------------------------------------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 }