1 8 package org.codehaus.aspectwerkz.transform.inlining; 9 10 import org.codehaus.aspectwerkz.util.ContextClassLoader; 11 import org.codehaus.aspectwerkz.reflect.ClassInfo; 12 import org.codehaus.aspectwerkz.reflect.MethodInfo; 13 import org.codehaus.aspectwerkz.reflect.ConstructorInfo; 14 import org.codehaus.aspectwerkz.reflect.FieldInfo; 15 import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo; 16 import org.codehaus.aspectwerkz.transform.TransformationConstants; 17 import org.codehaus.aspectwerkz.transform.AspectWerkzPreProcessor; 18 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException; 19 import org.objectweb.asm.ClassWriter; 20 import org.objectweb.asm.CodeVisitor; 21 import org.objectweb.asm.Type; 22 import org.objectweb.asm.Label; 23 import org.objectweb.asm.ClassReader; 24 25 import java.io.File ; 26 import java.io.FileOutputStream ; 27 import java.io.IOException ; 28 import java.lang.reflect.Constructor ; 29 import java.lang.reflect.Method ; 30 import java.lang.reflect.InvocationTargetException ; 31 import java.security.ProtectionDomain ; 32 import java.security.AccessController ; 33 import java.security.PrivilegedAction ; 34 35 41 public class AsmHelper implements TransformationConstants { 42 43 public final static ClassInfo INTEGER = JavaClassInfo.getClassInfo(Integer.TYPE); 44 public final static ClassInfo VOID = JavaClassInfo.getClassInfo(Void.TYPE); 45 public final static ClassInfo BOOLEAN = JavaClassInfo.getClassInfo(Boolean.TYPE); 46 public final static ClassInfo BYTE = JavaClassInfo.getClassInfo(Byte.TYPE); 47 public final static ClassInfo CHARACTER = JavaClassInfo.getClassInfo(Character.TYPE); 48 public final static ClassInfo SHORT = JavaClassInfo.getClassInfo(Short.TYPE); 49 public final static ClassInfo DOUBLE = JavaClassInfo.getClassInfo(Double.TYPE); 50 public final static ClassInfo FLOAT = JavaClassInfo.getClassInfo(Float.TYPE); 51 public final static ClassInfo LONG = JavaClassInfo.getClassInfo(Long.TYPE); 52 53 private static Class CLASS_LOADER; 54 private static Method CLASS_LOADER_DEFINE; 55 private static final ProtectionDomain PROTECTION_DOMAIN; 56 57 static { 58 PROTECTION_DOMAIN = (ProtectionDomain )AccessController.doPrivileged(new PrivilegedAction () { 59 public Object run() { 60 return AsmHelper.class.getProtectionDomain(); 61 } 62 }); 63 64 AccessController.doPrivileged(new PrivilegedAction () { 65 public Object run() { 66 try { 67 CLASS_LOADER = Class.forName(CLASS_LOADER_REFLECT_CLASS_NAME); 68 CLASS_LOADER_DEFINE = CLASS_LOADER.getDeclaredMethod( 69 DEFINE_CLASS_METHOD_NAME, new Class []{ 70 String .class, byte[].class, int.class, int.class, ProtectionDomain .class 71 } 72 ); 73 CLASS_LOADER_DEFINE.setAccessible(true); 74 } catch (Throwable t) { 75 throw new Error (t.toString()); 76 } 77 return null; 78 } 79 }); 80 } 81 82 83 84 87 public final static boolean IS_JAVA_5; 88 public static int JAVA_VERSION = V1_3; 89 90 static { 91 Class annotation = null; 92 try { 93 annotation = Class.forName("java.lang.annotation.Annotation"); 94 ClassReader cr = new ClassReader("java.lang.annotation.Annotation"); 95 JAVA_VERSION = V1_5; 96 } catch (Throwable e) { 97 annotation = null; 98 } 99 if (annotation == null) { 100 IS_JAVA_5 = false; 101 } else { 102 IS_JAVA_5 = true; 103 } 104 } 105 106 113 public static ClassWriter newClassWriter(boolean computeMax) { 114 return new ClassWriter(computeMax, true); 115 } 116 117 123 public static Type[] getArgumentTypes(final Constructor constructor) { 124 Class [] classes = constructor.getParameterTypes(); 125 Type[] types = new Type[classes.length]; 126 for (int i = classes.length - 1; i >= 0; --i) { 127 types[i] = Type.getType(classes[i]); 128 } 129 return types; 130 } 131 132 140 public static void dumpClass(final String dumpDir, final String className, final byte[] bytes) 141 throws IOException { 142 final File dir; 143 if (className.lastIndexOf('/')>0) { 144 dir = new File (dumpDir + File.separator + className.substring(0, className.lastIndexOf('/'))); 145 } else { 146 dir = new File (dumpDir); 147 } 148 dir.mkdirs(); 149 String fileName = dumpDir + File.separator + className + ".class"; 150 if (AspectWerkzPreProcessor.VERBOSE) { 151 System.out.println("AW INFO: dumping class " + className + " to " + dumpDir); 152 } 153 FileOutputStream os = new FileOutputStream (fileName); 154 os.write(bytes); 155 os.close(); 156 } 157 158 166 public static void dumpClass(final String dumpDir, final String className, final ClassWriter cw) 167 throws IOException { 168 File dir = new File (dumpDir + File.separator + className.substring(0, className.lastIndexOf('/'))); 169 dir.mkdirs(); 170 String fileName = dumpDir + File.separator + className + ".class"; 171 if (AspectWerkzPreProcessor.VERBOSE) { 172 System.out.println("AW INFO: dumping class " + className + " to " + dumpDir); 173 } 174 FileOutputStream os = new FileOutputStream (fileName); 175 os.write(cw.toByteArray()); 176 os.close(); 177 } 178 179 187 public static Class defineClass(ClassLoader loader, final byte[] bytes, final String name) { 188 String className = name.replace('/', '.'); 189 try { 190 if (loader == null) { 191 loader = ContextClassLoader.getLoader(); 192 } 193 194 Object [] args = new Object []{ 198 className, bytes, new Integer (0), new Integer (bytes.length), PROTECTION_DOMAIN 199 }; 200 Class clazz = (Class ) CLASS_LOADER_DEFINE.invoke(loader, args); 201 202 return clazz; 204 205 } catch (InvocationTargetException e) { 206 if (e.getTargetException() instanceof LinkageError ) { 209 Class failoverJoinpointClass = forName(loader, className); 210 if (failoverJoinpointClass != null) { 211 return failoverJoinpointClass; 212 } 213 } 214 throw new WrappedRuntimeException(e); 215 } catch (Exception e) { 216 throw new WrappedRuntimeException(e); 217 } 218 } 219 220 227 public static Class forName(ClassLoader loader, final String name) { 228 String className = name.replace('/', '.'); 229 try { 230 if (loader == null) { 231 loader = ContextClassLoader.getLoader(); 232 } 233 return Class.forName(className, false, loader); 235 } catch (Exception e) { 236 return null; 237 } 238 } 239 240 248 public static int calculateMethodHash(final String name, final String desc) { 249 int hash = 17; 250 hash = (37 * hash) + name.replace('/', '.').hashCode(); 251 Type[] argumentTypes = Type.getArgumentTypes(desc); 252 for (int i = 0; i < argumentTypes.length; i++) { 253 hash = (37 * hash) 254 + AsmHelper.convertTypeDescToReflectDesc(argumentTypes[i].getDescriptor()).hashCode(); 255 } 256 return hash; 257 } 258 259 265 public static int calculateConstructorHash(final String desc) { 266 return AsmHelper.calculateMethodHash(INIT_METHOD_NAME, desc); 267 } 268 269 284 291 public static int calculateFieldHash(final String name, final String desc) { 292 int hash = 17; 293 hash = (37 * hash) + name.hashCode(); 294 Type type = Type.getType(desc); 295 hash = (37 * hash) + AsmHelper.convertTypeDescToReflectDesc(type.getDescriptor()).hashCode(); 296 return hash; 297 } 298 299 305 public static int calculateClassHash(final String declaringType) { 306 return AsmHelper.convertTypeDescToReflectDesc(declaringType).hashCode(); 307 } 308 309 316 public static String convertArrayTypeName(final String typeName) { 317 int index = typeName.lastIndexOf('['); 318 if (index != -1) { 319 StringBuffer arrayType = new StringBuffer (); 320 if (typeName.endsWith("I")) { 321 arrayType.append("int"); 322 } else if (typeName.endsWith("J")) { 323 arrayType.append("long"); 324 } else if (typeName.endsWith("S")) { 325 arrayType.append("short"); 326 } else if (typeName.endsWith("F")) { 327 arrayType.append("float"); 328 } else if (typeName.endsWith("D")) { 329 arrayType.append("double"); 330 } else if (typeName.endsWith("Z")) { 331 arrayType.append("boolean"); 332 } else if (typeName.endsWith("C")) { 333 arrayType.append("char"); 334 } else if (typeName.endsWith("B")) { 335 arrayType.append("byte"); 336 } else { 337 arrayType.append(typeName.substring(index + 2, typeName.length() - 1)); 338 } 339 for (int i = 0; i < (index + 1); i++) { 340 arrayType.append("[]"); 341 } 342 return arrayType.toString(); 343 } else { 344 return typeName; 345 } 346 } 347 348 355 public static String convertTypeDescToReflectDesc(final String typeDesc) { 356 if (typeDesc == null) { 357 return null; 358 } 359 String result = null; 360 if (typeDesc.startsWith("[")) { 362 result = typeDesc; 363 } else { 364 if (typeDesc.startsWith("L") && typeDesc.endsWith(";")) { 366 result = typeDesc.substring(1, typeDesc.length() - 1); 367 } else { 368 if (typeDesc.equals("I")) { 370 result = "int"; 371 } else if (typeDesc.equals("J")) { 372 result = "long"; 373 } else if (typeDesc.equals("S")) { 374 result = "short"; 375 } else if (typeDesc.equals("F")) { 376 result = "float"; 377 } else if (typeDesc.equals("D")) { 378 result = "double"; 379 } else if (typeDesc.equals("Z")) { 380 result = "boolean"; 381 } else if (typeDesc.equals("C")) { 382 result = "char"; 383 } else if (typeDesc.equals("B")) { 384 result = "byte"; 385 } else { 386 throw new RuntimeException ("unknown primitive type " + typeDesc); 387 } 388 } 389 } 390 return result.replace('/', '.'); 391 } 392 393 399 public static String convertReflectDescToTypeDesc(final String desc) { 400 if (desc == null) { 401 return null; 402 } 403 String typeDesc = desc; 404 int dimension = 0; 405 char[] arr = desc.toCharArray(); 406 for (int i = 0; i < arr.length; i++) { 407 if (arr[i] == ']') { 408 dimension++; 409 } 410 } 411 typeDesc = desc.substring(0, desc.length() - dimension * 2); 412 if (typeDesc.equals("int")) { 413 typeDesc = "I"; 414 } else if (typeDesc.equals("short")) { 415 typeDesc = "S"; 416 } else if (typeDesc.equals("long")) { 417 typeDesc = "J"; 418 } else if (typeDesc.equals("float")) { 419 typeDesc = "F"; 420 } else if (typeDesc.equals("double")) { 421 typeDesc = "D"; 422 } else if (typeDesc.equals("byte")) { 423 typeDesc = "B"; 424 } else if (typeDesc.equals("char")) { 425 typeDesc = "C"; 426 } else if (typeDesc.equals("boolean")) { 427 typeDesc = "Z"; 428 } else { 429 typeDesc = 'L' + typeDesc + ';'; 430 } 431 for (int i = 0; i < dimension; i++) { 432 typeDesc = '[' + typeDesc; 433 } 434 return typeDesc.replace('.', '/'); 435 } 436 437 443 public static void addReturnStatement(final CodeVisitor mv, final Type type) { 444 switch (type.getSort()) { 445 case Type.VOID: 446 mv.visitInsn(RETURN); 447 break; 448 case Type.LONG: 449 mv.visitInsn(LRETURN); 450 break; 451 case Type.INT: 452 mv.visitInsn(IRETURN); 453 break; 454 case Type.SHORT: 455 mv.visitInsn(IRETURN); 456 break; 457 case Type.DOUBLE: 458 mv.visitInsn(DRETURN); 459 break; 460 case Type.FLOAT: 461 mv.visitInsn(FRETURN); 462 break; 463 case Type.BYTE: 464 mv.visitInsn(IRETURN); 465 break; 466 case Type.BOOLEAN: 467 mv.visitInsn(IRETURN); 468 break; 469 case Type.CHAR: 470 mv.visitInsn(IRETURN); 471 break; 472 case Type.ARRAY: 473 mv.visitInsn(ARETURN); 474 break; 475 case Type.OBJECT: 476 mv.visitInsn(ARETURN); 477 break; 478 } 479 } 480 481 487 public static void loadArgumentTypes(final CodeVisitor mv, final Type[] argumentTypes, final boolean staticMethod) { 488 int index; 489 if (staticMethod) { 490 index = 0; 491 } else { 492 index = 1; 493 } 494 for (int i = 0; i < argumentTypes.length; i++) { 495 index = loadType(mv, index, argumentTypes[i]); 496 } 497 } 498 499 507 public static int loadType(final CodeVisitor cv, int index, final Type type) { 508 switch (type.getSort()) { 509 case Type.LONG: 510 cv.visitVarInsn(LLOAD, index++); 511 index++; 512 break; 513 case Type.INT: 514 cv.visitVarInsn(ILOAD, index++); 515 break; 516 case Type.SHORT: 517 cv.visitVarInsn(ILOAD, index++); 518 break; 519 case Type.DOUBLE: 520 cv.visitVarInsn(DLOAD, index++); 521 index++; 522 break; 523 case Type.FLOAT: 524 cv.visitVarInsn(FLOAD, index++); 525 break; 526 case Type.BYTE: 527 cv.visitVarInsn(ILOAD, index++); 528 break; 529 case Type.BOOLEAN: 530 cv.visitVarInsn(ILOAD, index++); 531 break; 532 case Type.CHAR: 533 cv.visitVarInsn(ILOAD, index++); 534 break; 535 case Type.ARRAY: 536 cv.visitVarInsn(ALOAD, index++); 537 break; 538 case Type.OBJECT: 539 cv.visitVarInsn(ALOAD, index++); 540 break; 541 } 542 return index; 543 } 544 545 553 public static int storeType(final CodeVisitor cv, int index, final Type type) { 554 switch (type.getSort()) { 555 case Type.VOID: 556 break; 557 case Type.LONG: 558 cv.visitVarInsn(LSTORE, index++); 559 index++; 560 break; 561 case Type.INT: 562 cv.visitVarInsn(ISTORE, index++); 563 break; 564 case Type.SHORT: 565 cv.visitVarInsn(ISTORE, index++); 566 break; 567 case Type.DOUBLE: 568 cv.visitVarInsn(DSTORE, index++); 569 index++; 570 break; 571 case Type.FLOAT: 572 cv.visitVarInsn(FSTORE, index++); 573 break; 574 case Type.BYTE: 575 cv.visitVarInsn(ISTORE, index++); 576 break; 577 case Type.BOOLEAN: 578 cv.visitVarInsn(ISTORE, index++); 579 break; 580 case Type.CHAR: 581 cv.visitVarInsn(ISTORE, index++); 582 break; 583 case Type.ARRAY: 584 cv.visitVarInsn(ASTORE, index++); 585 break; 586 case Type.OBJECT: 587 cv.visitVarInsn(ASTORE, index++); 588 break; 589 } 590 return index; 591 } 592 593 599 public static void loadIntegerConstant(final CodeVisitor cv, final int index) { 600 switch (index) { 601 case 0: 602 cv.visitInsn(ICONST_0); 603 break; 604 case 1: 605 cv.visitInsn(ICONST_1); 606 break; 607 case 2: 608 cv.visitInsn(ICONST_2); 609 break; 610 case 3: 611 cv.visitInsn(ICONST_3); 612 break; 613 case 4: 614 cv.visitInsn(ICONST_4); 615 break; 616 case 5: 617 cv.visitInsn(ICONST_5); 618 break; 619 default: 620 cv.visitIntInsn(BIPUSH, index); 621 break; 622 } 623 } 624 625 631 public static void prepareWrappingOfPrimitiveType(final CodeVisitor cv, final Type type) { 632 switch (type.getSort()) { 633 case Type.SHORT: 634 cv.visitTypeInsn(NEW, SHORT_CLASS_NAME); 635 cv.visitInsn(DUP); 636 break; 637 case Type.INT: 638 cv.visitTypeInsn(NEW, INTEGER_CLASS_NAME); 639 cv.visitInsn(DUP); 640 break; 641 case Type.LONG: 642 cv.visitTypeInsn(NEW, LONG_CLASS_NAME); 643 cv.visitInsn(DUP); 644 break; 645 case Type.FLOAT: 646 cv.visitTypeInsn(NEW, FLOAT_CLASS_NAME); 647 cv.visitInsn(DUP); 648 break; 649 case Type.DOUBLE: 650 cv.visitTypeInsn(NEW, DOUBLE_CLASS_NAME); 651 cv.visitInsn(DUP); 652 break; 653 case Type.BYTE: 654 cv.visitTypeInsn(NEW, BYTE_CLASS_NAME); 655 cv.visitInsn(DUP); 656 break; 657 case Type.BOOLEAN: 658 cv.visitTypeInsn(NEW, BOOLEAN_CLASS_NAME); 659 cv.visitInsn(DUP); 660 break; 661 case Type.CHAR: 662 cv.visitTypeInsn(NEW, CHARACTER_CLASS_NAME); 663 cv.visitInsn(DUP); 664 break; 665 } 666 } 667 668 674 public static void wrapPrimitiveType(final CodeVisitor cv, final Type type) { 675 switch (type.getSort()) { 676 case Type.VOID: 677 cv.visitInsn(ACONST_NULL); 678 break; 679 case Type.SHORT: 680 cv.visitMethodInsn( 681 INVOKESPECIAL, 682 SHORT_CLASS_NAME, 683 INIT_METHOD_NAME, 684 SHORT_CLASS_INIT_METHOD_SIGNATURE 685 ); 686 break; 687 case Type.INT: 688 cv.visitMethodInsn( 689 INVOKESPECIAL, 690 INTEGER_CLASS_NAME, 691 INIT_METHOD_NAME, 692 INTEGER_CLASS_INIT_METHOD_SIGNATURE 693 ); 694 break; 695 case Type.LONG: 696 cv.visitMethodInsn(INVOKESPECIAL, LONG_CLASS_NAME, INIT_METHOD_NAME, LONG_CLASS_INIT_METHOD_SIGNATURE); 697 break; 698 case Type.FLOAT: 699 cv.visitMethodInsn( 700 INVOKESPECIAL, 701 FLOAT_CLASS_NAME, 702 INIT_METHOD_NAME, 703 FLOAT_CLASS_INIT_METHOD_SIGNATURE 704 ); 705 break; 706 case Type.DOUBLE: 707 cv.visitMethodInsn( 708 INVOKESPECIAL, 709 DOUBLE_CLASS_NAME, 710 INIT_METHOD_NAME, 711 DOUBLE_CLASS_INIT_METHOD_SIGNATURE 712 ); 713 break; 714 case Type.BYTE: 715 cv.visitMethodInsn(INVOKESPECIAL, BYTE_CLASS_NAME, INIT_METHOD_NAME, BYTE_CLASS_INIT_METHOD_SIGNATURE); 716 break; 717 case Type.BOOLEAN: 718 cv.visitMethodInsn( 719 INVOKESPECIAL, 720 BOOLEAN_CLASS_NAME, 721 INIT_METHOD_NAME, 722 BOOLEAN_CLASS_INIT_METHOD_SIGNATURE 723 ); 724 break; 725 case Type.CHAR: 726 cv.visitMethodInsn( 727 INVOKESPECIAL, 728 CHARACTER_CLASS_NAME, 729 INIT_METHOD_NAME, 730 CHARACTER_CLASS_INIT_METHOD_SIGNATURE 731 ); 732 break; 733 } 734 } 735 736 744 public static void unwrapType(final CodeVisitor cv, final Type type) { 745 switch (type.getSort()) { 747 case Type.OBJECT: 748 String objectTypeName = type.getClassName().replace('.', '/'); 749 cv.visitTypeInsn(CHECKCAST, objectTypeName); 750 return; 751 case Type.ARRAY: 752 cv.visitTypeInsn(CHECKCAST, type.getDescriptor()); 753 return; 754 case Type.VOID: 755 return; 756 } 757 Label l0If = new Label(); 759 Label l1End = new Label(); 760 cv.visitInsn(DUP); 762 cv.visitJumpInsn(IFNONNULL, l0If); 763 cv.visitInsn(POP); 765 addDefaultValue(cv, type); 766 cv.visitJumpInsn(GOTO, l1End); 768 cv.visitLabel(l0If); 770 switch (type.getSort()) { 771 case Type.SHORT: 772 cv.visitTypeInsn(CHECKCAST, SHORT_CLASS_NAME); 773 cv.visitMethodInsn( 774 INVOKEVIRTUAL, 775 SHORT_CLASS_NAME, 776 SHORT_VALUE_METHOD_NAME, 777 SHORT_VALUE_METHOD_SIGNATURE 778 ); 779 break; 780 case Type.INT: 781 cv.visitTypeInsn(CHECKCAST, INTEGER_CLASS_NAME); 782 cv.visitMethodInsn( 783 INVOKEVIRTUAL, 784 INTEGER_CLASS_NAME, 785 INT_VALUE_METHOD_NAME, 786 INT_VALUE_METHOD_SIGNATURE 787 ); 788 break; 789 case Type.LONG: 790 cv.visitTypeInsn(CHECKCAST, LONG_CLASS_NAME); 791 cv.visitMethodInsn( 792 INVOKEVIRTUAL, LONG_CLASS_NAME, LONG_VALUE_METHOD_NAME, LONG_VALUE_METHOD_SIGNATURE 793 ); 794 break; 795 case Type.FLOAT: 796 cv.visitTypeInsn(CHECKCAST, FLOAT_CLASS_NAME); 797 cv.visitMethodInsn( 798 INVOKEVIRTUAL, 799 FLOAT_CLASS_NAME, 800 FLOAT_VALUE_METHOD_NAME, 801 FLOAT_VALUE_METHOD_SIGNATURE 802 ); 803 break; 804 case Type.DOUBLE: 805 cv.visitTypeInsn(CHECKCAST, DOUBLE_CLASS_NAME); 806 cv.visitMethodInsn( 807 INVOKEVIRTUAL, 808 DOUBLE_CLASS_NAME, 809 DOUBLE_VALUE_METHOD_NAME, 810 DOUBLE_VALUE_METHOD_SIGNATURE 811 ); 812 break; 813 case Type.BYTE: 814 cv.visitTypeInsn(CHECKCAST, BYTE_CLASS_NAME); 815 cv.visitMethodInsn( 816 INVOKEVIRTUAL, BYTE_CLASS_NAME, BYTE_VALUE_METHOD_NAME, BYTE_VALUE_METHOD_SIGNATURE 817 ); 818 break; 819 case Type.BOOLEAN: 820 cv.visitTypeInsn(CHECKCAST, BOOLEAN_CLASS_NAME); 821 cv.visitMethodInsn( 822 INVOKEVIRTUAL, 823 BOOLEAN_CLASS_NAME, 824 BOOLEAN_VALUE_METHOD_NAME, 825 BOOLEAN_VALUE_METHOD_SIGNATURE 826 ); 827 break; 828 case Type.CHAR: 829 cv.visitTypeInsn(CHECKCAST, CHARACTER_CLASS_NAME); 830 cv.visitMethodInsn( 831 INVOKEVIRTUAL, 832 CHARACTER_CLASS_NAME, 833 CHAR_VALUE_METHOD_NAME, 834 CHAR_VALUE_METHOD_SIGNATURE 835 ); 836 break; 837 } 838 cv.visitLabel(l1End); 839 } 840 841 847 public static void addDefaultValue(final CodeVisitor cv, final Type type) { 848 switch (type.getSort()) { 849 case Type.OBJECT: 850 cv.visitInsn(ACONST_NULL); 851 break; 852 case Type.ARRAY: 853 cv.visitInsn(ACONST_NULL); 854 break; 855 case Type.INT: 856 cv.visitInsn(ICONST_0); 857 break; 858 case Type.LONG: 859 cv.visitInsn(LCONST_0); 860 break; 861 case Type.SHORT: 862 cv.visitInsn(ICONST_0); 863 break; 864 case Type.FLOAT: 865 cv.visitInsn(FCONST_0); 866 break; 867 case Type.DOUBLE: 868 cv.visitInsn(DCONST_0); 869 break; 870 case Type.BYTE: 871 cv.visitInsn(ICONST_0); 872 break; 873 case Type.BOOLEAN: 874 cv.visitInsn(ICONST_0); 875 break; 876 case Type.CHAR: 877 cv.visitInsn(ICONST_0); 878 break; 879 } 880 } 881 882 888 public static void addNullableString(final CodeVisitor cv, final String value) { 889 if (value == null) { 890 cv.visitInsn(ACONST_NULL); 891 } else { 892 cv.visitLdcInsn(value); 893 } 894 } 895 896 902 public static int getRegisterDepth(final Type[] typesOnStack) { 903 int depth = 0; 904 for (int i = 0; i < typesOnStack.length; i++) { 905 Type type = typesOnStack[i]; 906 depth++; 907 switch (type.getSort()) { 908 case Type.LONG: 909 depth++; 910 break; 911 case Type.DOUBLE: 912 depth++; 913 break; 914 } 915 } 916 return depth; 917 } 918 919 926 public static int getRegisterIndexOf(final Type[] typesOnStack, final int typeIndex) { 927 int depth = 0; 928 for (int i = 0; i < typeIndex; i++) { 929 Type type = typesOnStack[i]; 930 depth++; 931 switch (type.getSort()) { 932 case Type.LONG: 933 depth++; 934 break; 935 case Type.DOUBLE: 936 depth++; 937 break; 938 } 939 } 940 return depth; 941 } 942 943 951 public static int getTypeIndexOf(final Type[] typesOnStack, final int registerIndex) { 952 for (int i = 0; i < typesOnStack.length; i++) { 953 int presumedRegisterIndex = getRegisterIndexOf(typesOnStack, i); 954 if (registerIndex == presumedRegisterIndex) { 955 return i; 956 } 957 } 958 return -1; 959 } 960 961 967 public static boolean isPrimitive(final Type returnType) { 968 if (returnType.getSort() == Type.INT || 969 returnType.getSort() == Type.SHORT || 970 returnType.getSort() == Type.LONG || 971 returnType.getSort() == Type.FLOAT || 972 returnType.getSort() == Type.DOUBLE || 973 returnType.getSort() == Type.BYTE || 974 returnType.getSort() == Type.CHAR || 975 returnType.getSort() == Type.BOOLEAN || 976 returnType.getSort() == Type.VOID) { 977 return true; 978 } else { 979 return false; 980 } 981 } 982 983 990 public static int incrementIndex(int index, final Type type) { 991 if (type.getSort() == Type.LONG || type.getSort() == Type.DOUBLE) { 992 index += 2; 993 } else { 994 index++; 995 } 996 return index; 997 } 998 999 1006 public static String getMethodDescriptor(final MethodInfo method) { 1007 ClassInfo[] parameters = method.getParameterTypes(); 1008 StringBuffer buf = new StringBuffer (); 1009 buf.append('('); 1010 for (int i = 0; i < parameters.length; ++i) { 1011 getClassDescriptor(buf, parameters[i]); 1012 } 1013 buf.append(')'); 1014 getClassDescriptor(buf, method.getReturnType()); 1015 return buf.toString(); 1016 } 1017 1018 1024 public static String getConstructorDescriptor(final ConstructorInfo constructor) { 1025 ClassInfo[] parameters = constructor.getParameterTypes(); 1026 StringBuffer buf = new StringBuffer (); 1027 buf.append('('); 1028 for (int i = 0; i < parameters.length; ++i) { 1029 getClassDescriptor(buf, parameters[i]); 1030 } 1031 buf.append(')'); 1032 getClassDescriptor(buf, VOID); 1033 return buf.toString(); 1034 } 1035 1036 1042 public static String getFieldDescriptor(final FieldInfo field) { 1043 return getClassDescriptor(field.getType()); 1044 } 1045 1046 1055 public static String getClassDescriptor(final ClassInfo c) { 1056 StringBuffer buf = new StringBuffer (); 1057 getClassDescriptor(buf, c); 1058 return buf.toString(); 1059 } 1060 1061 1068 private static void getClassDescriptor(final StringBuffer buf, final ClassInfo klass) { 1069 ClassInfo d = klass; 1070 while (true) { 1071 if (d.isPrimitive()) { 1072 char car; 1073 if (d.equals(INTEGER)) { 1074 car = 'I'; 1075 } else if (d.equals(VOID)) { 1076 car = 'V'; 1077 } else if (d.equals(BOOLEAN)) { 1078 car = 'Z'; 1079 } else if (d.equals(BYTE)) { 1080 car = 'B'; 1081 } else if (d.equals(CHARACTER)) { 1082 car = 'C'; 1083 } else if (d.equals(SHORT)) { 1084 car = 'S'; 1085 } else if (d.equals(DOUBLE)) { 1086 car = 'D'; 1087 } else if (d.equals(FLOAT)) { 1088 car = 'F'; 1089 } else if (d.equals(LONG)) { 1090 car = 'J'; 1091 } else { 1092 throw new Error ("should not happen"); 1093 } 1094 buf.append(car); 1095 return; 1096 } else if (d.isArray()) { 1097 buf.append('['); 1098 d = d.getComponentType(); 1099 } else { 1100 buf.append('L'); 1101 String name = d.getName(); 1102 int len = name.length(); 1103 for (int i = 0; i < len; ++i) { 1104 char car = name.charAt(i); 1105 buf.append(car == '.' ? '/' : car); 1106 } 1107 buf.append(';'); 1108 return; 1109 } 1110 } 1111 } 1112 1113 1122 public static Type[] getArgumentTypes(final MethodInfo method) { 1123 ClassInfo[] classes = method.getParameterTypes(); 1124 Type[] types = new Type[classes.length]; 1125 for (int i = classes.length - 1; i >= 0; --i) { 1126 types[i] = getType(classes[i]); 1127 } 1128 return types; 1129 } 1130 1131 1138 public static Type getType(final ClassInfo c) { 1139 if (c.isPrimitive()) { 1140 if (c.equals(INTEGER)) { 1141 return Type.INT_TYPE; 1142 } else if (c.equals(VOID)) { 1143 return Type.VOID_TYPE; 1144 } else if (c.equals(BOOLEAN)) { 1145 return Type.BOOLEAN_TYPE; 1146 } else if (c.equals(BYTE)) { 1147 return Type.BYTE_TYPE; 1148 } else if (c.equals(CHARACTER)) { 1149 return Type.CHAR_TYPE; 1150 } else if (c.equals(SHORT)) { 1151 return Type.SHORT_TYPE; 1152 } else if (c.equals(DOUBLE)) { 1153 return Type.DOUBLE_TYPE; 1154 } else if (c.equals(FLOAT)) { 1155 return Type.FLOAT_TYPE; 1156 } else if (c.equals(LONG)) { 1157 return Type.LONG_TYPE; 1158 } else { 1159 throw new Error ("should not happen"); 1160 } 1161 } else { 1162 return Type.getType(getClassDescriptor(c)); 1163 } 1164 } 1165 1166} | Popular Tags |