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