1 4 package com.tc.aspectwerkz.transform.inlining; 5 6 import com.tc.asm.ClassWriter; 7 import com.tc.asm.MethodVisitor; 8 import com.tc.asm.Type; 9 import com.tc.asm.Label; 10 import com.tc.asm.ClassReader; 11 12 import com.tc.aspectwerkz.exception.WrappedRuntimeException; 13 import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo; 14 import com.tc.aspectwerkz.reflect.ClassInfo; 15 import com.tc.aspectwerkz.reflect.FieldInfo; 16 import com.tc.aspectwerkz.reflect.ConstructorInfo; 17 import com.tc.aspectwerkz.reflect.MethodInfo; 18 import com.tc.aspectwerkz.transform.Properties; 19 import com.tc.aspectwerkz.transform.TransformationConstants; 20 import com.tc.aspectwerkz.util.ContextClassLoader; 21 22 23 import java.io.File ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.lang.reflect.Constructor ; 27 import java.lang.reflect.Method ; 28 import java.lang.reflect.InvocationTargetException ; 29 import java.security.ProtectionDomain ; 30 import java.security.AccessController ; 31 import java.security.PrivilegedAction ; 32 33 39 public class AsmHelper implements TransformationConstants { 40 41 public final static ClassInfo INTEGER = JavaClassInfo.getClassInfo(Integer.TYPE); 42 public final static ClassInfo VOID = JavaClassInfo.getClassInfo(Void.TYPE); 43 public final static ClassInfo BOOLEAN = JavaClassInfo.getClassInfo(Boolean.TYPE); 44 public final static ClassInfo BYTE = JavaClassInfo.getClassInfo(Byte.TYPE); 45 public final static ClassInfo CHARACTER = JavaClassInfo.getClassInfo(Character.TYPE); 46 public final static ClassInfo SHORT = JavaClassInfo.getClassInfo(Short.TYPE); 47 public final static ClassInfo DOUBLE = JavaClassInfo.getClassInfo(Double.TYPE); 48 public final static ClassInfo FLOAT = JavaClassInfo.getClassInfo(Float.TYPE); 49 public final static ClassInfo LONG = JavaClassInfo.getClassInfo(Long.TYPE); 50 51 private static Class CLASS_LOADER; 52 private static Method CLASS_LOADER_DEFINE; 53 private static final ProtectionDomain PROTECTION_DOMAIN; 54 55 static { 56 PROTECTION_DOMAIN = (ProtectionDomain ) AccessController.doPrivileged(new PrivilegedAction () { 57 public Object run() { 58 return AsmHelper.class.getProtectionDomain(); 59 } 60 }); 61 62 AccessController.doPrivileged(new PrivilegedAction () { 63 public Object run() { 64 try { 65 CLASS_LOADER = Class.forName(CLASS_LOADER_REFLECT_CLASS_NAME); 66 CLASS_LOADER_DEFINE = CLASS_LOADER.getDeclaredMethod( 67 DEFINE_CLASS_METHOD_NAME, new Class []{ 68 String .class, byte[].class, int.class, int.class, ProtectionDomain .class 69 } 70 ); 71 CLASS_LOADER_DEFINE.setAccessible(true); 72 } catch (Throwable t) { 73 throw new Error (t.toString()); 74 } 75 return null; 76 } 77 }); 78 } 79 80 81 84 public final static boolean IS_JAVA_5; 85 public static int JAVA_VERSION = V1_3; 86 87 static { 88 Class annotation = null; 89 try { 90 annotation = Class.forName("java.lang.annotation.Annotation"); 91 ClassReader cr = new ClassReader("java.lang.annotation.Annotation"); 92 JAVA_VERSION = V1_5; 93 } catch (Throwable e) { 94 annotation = null; 95 } 96 if (annotation == null) { 97 IS_JAVA_5 = false; 98 } else { 99 IS_JAVA_5 = true; 100 } 101 } 102 103 110 public static ClassWriter newClassWriter(boolean computeMax) { 111 return new ClassWriter(computeMax, true); 112 } 113 114 120 public static Type[] getArgumentTypes(final Constructor constructor) { 121 Class [] classes = constructor.getParameterTypes(); 122 Type[] types = new Type[classes.length]; 123 for (int i = classes.length - 1; i >= 0; --i) { 124 types[i] = Type.getType(classes[i]); 125 } 126 return types; 127 } 128 129 137 public static void dumpClass(final String dumpDir, final String className, final byte[] bytes) 138 throws IOException { 139 final File dir; 140 if (className.lastIndexOf('/') > 0) { 141 dir = new File (dumpDir + File.separator + className.substring(0, className.lastIndexOf('/'))); 142 } else { 143 dir = new File (dumpDir); 144 } 145 dir.mkdirs(); 146 String fileName = dumpDir + File.separator + className + ".class"; 147 if (Properties.PRINT_DEPLOYMENT_INFO) { 148 System.out.println("AW INFO: dumping class " + className + " to " + dumpDir); 149 } 150 FileOutputStream os = new FileOutputStream (fileName); 151 os.write(bytes); 152 os.close(); 153 } 154 155 163 public static void dumpClass(final String dumpDir, final String className, final ClassWriter cw) 164 throws IOException { 165 String base = ""; 166 if (className.lastIndexOf('/') > 0) { 167 base = className.substring(0, className.lastIndexOf('/')); 168 } 169 File dir = new File (dumpDir + File.separator + base); 170 dir.mkdirs(); 171 String fileName = dumpDir + File.separator + className + ".class"; 172 if (Properties.PRINT_DEPLOYMENT_INFO) { 173 System.out.println("AW INFO: dumping class " + className + " to " + dumpDir); 174 } 175 FileOutputStream os = new FileOutputStream (fileName); 176 os.write(cw.toByteArray()); 177 os.close(); 178 } 179 180 188 public static Class defineClass(ClassLoader loader, final byte[] bytes, final String name) { 189 String className = name.replace('/', '.'); 190 try { 191 if (loader == null) { 192 loader = ContextClassLoader.getLoader(); 193 } 194 195 Object [] args = new Object []{ 196 className, bytes, new Integer (0), new Integer (bytes.length), PROTECTION_DOMAIN 197 }; 198 Class klass = (Class ) CLASS_LOADER_DEFINE.invoke(loader, args); 199 return klass; 200 201 } catch (InvocationTargetException e) { 202 if (e.getTargetException() instanceof LinkageError ) { 205 Class failoverJoinpointClass = forName(loader, className); 206 if (failoverJoinpointClass != null) { 207 return failoverJoinpointClass; 208 } 209 } 210 throw new WrappedRuntimeException(e); 211 } catch (Exception e) { 212 throw new WrappedRuntimeException(e); 213 } 214 } 215 216 223 public static Class forName(ClassLoader loader, final String name) { 224 String className = name.replace('/', '.'); 225 try { 226 if (loader == null) { 227 loader = ContextClassLoader.getLoader(); 228 } 229 return Class.forName(className, false, loader); 231 } catch (Exception e) { 232 return null; 233 } 234 } 235 236 244 public static int calculateMethodHash(final String name, final String desc) { 245 int hash = 17; 246 hash = (37 * hash) + name.replace('/', '.').hashCode(); 247 Type[] argumentTypes = Type.getArgumentTypes(desc); 248 for (int i = 0; i < argumentTypes.length; i++) { 249 hash = (37 * hash) 250 + AsmHelper.convertTypeDescToReflectDesc(argumentTypes[i].getDescriptor()).hashCode(); 251 } 252 return hash; 253 } 254 255 261 public static int calculateConstructorHash(final String desc) { 262 return AsmHelper.calculateMethodHash(INIT_METHOD_NAME, desc); 263 } 264 265 272 public static int calculateFieldHash(final String name, final String desc) { 273 int hash = 17; 274 hash = (37 * hash) + name.hashCode(); 275 Type type = Type.getType(desc); 276 hash = (37 * hash) + AsmHelper.convertTypeDescToReflectDesc(type.getDescriptor()).hashCode(); 277 return hash; 278 } 279 280 286 public static int calculateClassHash(final String declaringType) { 287 return AsmHelper.convertTypeDescToReflectDesc(declaringType).hashCode(); 288 } 289 290 297 public static String convertArrayTypeName(final String typeName) { 298 int index = typeName.lastIndexOf('['); 299 if (index != -1) { 300 StringBuffer arrayType = new StringBuffer (); 301 if (typeName.endsWith("I")) { 302 arrayType.append("int"); 303 } else if (typeName.endsWith("J")) { 304 arrayType.append("long"); 305 } else if (typeName.endsWith("S")) { 306 arrayType.append("short"); 307 } else if (typeName.endsWith("F")) { 308 arrayType.append("float"); 309 } else if (typeName.endsWith("D")) { 310 arrayType.append("double"); 311 } else if (typeName.endsWith("Z")) { 312 arrayType.append("boolean"); 313 } else if (typeName.endsWith("C")) { 314 arrayType.append("char"); 315 } else if (typeName.endsWith("B")) { 316 arrayType.append("byte"); 317 } else { 318 arrayType.append(typeName.substring(index + 2, typeName.length() - 1)); 319 } 320 for (int i = 0; i < (index + 1); i++) { 321 arrayType.append("[]"); 322 } 323 return arrayType.toString(); 324 } else { 325 return typeName; 326 } 327 } 328 329 336 public static String convertTypeDescToReflectDesc(final String typeDesc) { 337 if (typeDesc == null) { 338 return null; 339 } 340 String result = null; 341 if (typeDesc.startsWith("[")) { 343 result = typeDesc; 344 } else { 345 if (typeDesc.startsWith("L") && typeDesc.endsWith(";")) { 347 result = typeDesc.substring(1, typeDesc.length() - 1); 348 } else { 349 if (typeDesc.equals("I")) { 351 result = "int"; 352 } else if (typeDesc.equals("J")) { 353 result = "long"; 354 } else if (typeDesc.equals("S")) { 355 result = "short"; 356 } else if (typeDesc.equals("F")) { 357 result = "float"; 358 } else if (typeDesc.equals("D")) { 359 result = "double"; 360 } else if (typeDesc.equals("Z")) { 361 result = "boolean"; 362 } else if (typeDesc.equals("C")) { 363 result = "char"; 364 } else if (typeDesc.equals("B")) { 365 result = "byte"; 366 } else { 367 throw new RuntimeException ("unknown primitive type " + typeDesc); 368 } 369 } 370 } 371 return result.replace('/', '.'); 372 } 373 374 380 public static String convertReflectDescToTypeDesc(final String desc) { 381 if (desc == null) { 382 return null; 383 } 384 String typeDesc = desc; 385 int dimension = 0; 386 char[] arr = desc.toCharArray(); 387 for (int i = 0; i < arr.length; i++) { 388 if (arr[i] == ']') { 389 dimension++; 390 } 391 } 392 typeDesc = desc.substring(0, desc.length() - dimension * 2); 393 if (typeDesc.equals("int")) { 394 typeDesc = "I"; 395 } else if (typeDesc.equals("short")) { 396 typeDesc = "S"; 397 } else if (typeDesc.equals("long")) { 398 typeDesc = "J"; 399 } else if (typeDesc.equals("float")) { 400 typeDesc = "F"; 401 } else if (typeDesc.equals("double")) { 402 typeDesc = "D"; 403 } else if (typeDesc.equals("byte")) { 404 typeDesc = "B"; 405 } else if (typeDesc.equals("char")) { 406 typeDesc = "C"; 407 } else if (typeDesc.equals("boolean")) { 408 typeDesc = "Z"; 409 } else { 410 typeDesc = 'L' + typeDesc + ';'; 411 } 412 for (int i = 0; i < dimension; i++) { 413 typeDesc = '[' + typeDesc; 414 } 415 return typeDesc.replace('.', '/'); 416 } 417 418 424 public static void addReturnStatement(final MethodVisitor mv, final Type type) { 425 switch (type.getSort()) { 426 case Type.VOID: 427 mv.visitInsn(RETURN); 428 break; 429 case Type.LONG: 430 mv.visitInsn(LRETURN); 431 break; 432 case Type.INT: 433 mv.visitInsn(IRETURN); 434 break; 435 case Type.SHORT: 436 mv.visitInsn(IRETURN); 437 break; 438 case Type.DOUBLE: 439 mv.visitInsn(DRETURN); 440 break; 441 case Type.FLOAT: 442 mv.visitInsn(FRETURN); 443 break; 444 case Type.BYTE: 445 mv.visitInsn(IRETURN); 446 break; 447 case Type.BOOLEAN: 448 mv.visitInsn(IRETURN); 449 break; 450 case Type.CHAR: 451 mv.visitInsn(IRETURN); 452 break; 453 case Type.ARRAY: 454 mv.visitInsn(ARETURN); 455 break; 456 case Type.OBJECT: 457 mv.visitInsn(ARETURN); 458 break; 459 } 460 } 461 462 468 public static void loadArgumentTypes(final MethodVisitor mv, final Type[] argumentTypes, final boolean staticMethod) { 469 int index; 470 if (staticMethod) { 471 index = 0; 472 } else { 473 index = 1; 474 } 475 for (int i = 0; i < argumentTypes.length; i++) { 476 index = loadType(mv, index, argumentTypes[i]); 477 } 478 } 479 480 488 public static int loadType(final MethodVisitor cv, int index, final Type type) { 489 switch (type.getSort()) { 490 case Type.LONG: 491 cv.visitVarInsn(LLOAD, index++); 492 index++; 493 break; 494 case Type.INT: 495 cv.visitVarInsn(ILOAD, index++); 496 break; 497 case Type.SHORT: 498 cv.visitVarInsn(ILOAD, index++); 499 break; 500 case Type.DOUBLE: 501 cv.visitVarInsn(DLOAD, index++); 502 index++; 503 break; 504 case Type.FLOAT: 505 cv.visitVarInsn(FLOAD, index++); 506 break; 507 case Type.BYTE: 508 cv.visitVarInsn(ILOAD, index++); 509 break; 510 case Type.BOOLEAN: 511 cv.visitVarInsn(ILOAD, index++); 512 break; 513 case Type.CHAR: 514 cv.visitVarInsn(ILOAD, index++); 515 break; 516 case Type.ARRAY: 517 cv.visitVarInsn(ALOAD, index++); 518 break; 519 case Type.OBJECT: 520 cv.visitVarInsn(ALOAD, index++); 521 break; 522 } 523 return index; 524 } 525 526 534 public static int storeType(final MethodVisitor cv, int index, final Type type) { 535 switch (type.getSort()) { 536 case Type.VOID: 537 break; 538 case Type.LONG: 539 cv.visitVarInsn(LSTORE, index++); 540 index++; 541 break; 542 case Type.INT: 543 cv.visitVarInsn(ISTORE, index++); 544 break; 545 case Type.SHORT: 546 cv.visitVarInsn(ISTORE, index++); 547 break; 548 case Type.DOUBLE: 549 cv.visitVarInsn(DSTORE, index++); 550 index++; 551 break; 552 case Type.FLOAT: 553 cv.visitVarInsn(FSTORE, index++); 554 break; 555 case Type.BYTE: 556 cv.visitVarInsn(ISTORE, index++); 557 break; 558 case Type.BOOLEAN: 559 cv.visitVarInsn(ISTORE, index++); 560 break; 561 case Type.CHAR: 562 cv.visitVarInsn(ISTORE, index++); 563 break; 564 case Type.ARRAY: 565 cv.visitVarInsn(ASTORE, index++); 566 break; 567 case Type.OBJECT: 568 cv.visitVarInsn(ASTORE, index++); 569 break; 570 } 571 return index; 572 } 573 574 580 public static void loadStringConstant(final MethodVisitor cv, final String s) { 581 if (s != null) { 582 cv.visitLdcInsn(s); 583 } else { 584 cv.visitInsn(ACONST_NULL); 585 } 586 } 587 588 594 public static void loadIntegerConstant(final MethodVisitor cv, final int index) { 595 switch (index) { 596 case 0: 597 cv.visitInsn(ICONST_0); 598 break; 599 case 1: 600 cv.visitInsn(ICONST_1); 601 break; 602 case 2: 603 cv.visitInsn(ICONST_2); 604 break; 605 case 3: 606 cv.visitInsn(ICONST_3); 607 break; 608 case 4: 609 cv.visitInsn(ICONST_4); 610 break; 611 case 5: 612 cv.visitInsn(ICONST_5); 613 break; 614 default: 615 cv.visitIntInsn(BIPUSH, index); 616 break; 617 } 618 } 619 620 626 public static void prepareWrappingOfPrimitiveType(final MethodVisitor cv, final Type type) { 627 switch (type.getSort()) { 628 case Type.SHORT: 629 cv.visitTypeInsn(NEW, SHORT_CLASS_NAME); 630 cv.visitInsn(DUP); 631 break; 632 case Type.INT: 633 cv.visitTypeInsn(NEW, INTEGER_CLASS_NAME); 634 cv.visitInsn(DUP); 635 break; 636 case Type.LONG: 637 cv.visitTypeInsn(NEW, LONG_CLASS_NAME); 638 cv.visitInsn(DUP); 639 break; 640 case Type.FLOAT: 641 cv.visitTypeInsn(NEW, FLOAT_CLASS_NAME); 642 cv.visitInsn(DUP); 643 break; 644 case Type.DOUBLE: 645 cv.visitTypeInsn(NEW, DOUBLE_CLASS_NAME); 646 cv.visitInsn(DUP); 647 break; 648 case Type.BYTE: 649 cv.visitTypeInsn(NEW, BYTE_CLASS_NAME); 650 cv.visitInsn(DUP); 651 break; 652 case Type.BOOLEAN: 653 cv.visitTypeInsn(NEW, BOOLEAN_CLASS_NAME); 654 cv.visitInsn(DUP); 655 break; 656 case Type.CHAR: 657 cv.visitTypeInsn(NEW, CHARACTER_CLASS_NAME); 658 cv.visitInsn(DUP); 659 break; 660 } 661 } 662 663 669 public static void wrapPrimitiveType(final MethodVisitor cv, final Type type) { 670 switch (type.getSort()) { 671 case Type.VOID: 672 cv.visitInsn(ACONST_NULL); 673 break; 674 case Type.SHORT: 675 cv.visitMethodInsn( 676 INVOKESPECIAL, 677 SHORT_CLASS_NAME, 678 INIT_METHOD_NAME, 679 SHORT_CLASS_INIT_METHOD_SIGNATURE 680 ); 681 break; 682 case Type.INT: 683 cv.visitMethodInsn( 684 INVOKESPECIAL, 685 INTEGER_CLASS_NAME, 686 INIT_METHOD_NAME, 687 INTEGER_CLASS_INIT_METHOD_SIGNATURE 688 ); 689 break; 690 case Type.LONG: 691 cv.visitMethodInsn(INVOKESPECIAL, LONG_CLASS_NAME, INIT_METHOD_NAME, LONG_CLASS_INIT_METHOD_SIGNATURE); 692 break; 693 case Type.FLOAT: 694 cv.visitMethodInsn( 695 INVOKESPECIAL, 696 FLOAT_CLASS_NAME, 697 INIT_METHOD_NAME, 698 FLOAT_CLASS_INIT_METHOD_SIGNATURE 699 ); 700 break; 701 case Type.DOUBLE: 702 cv.visitMethodInsn( 703 INVOKESPECIAL, 704 DOUBLE_CLASS_NAME, 705 INIT_METHOD_NAME, 706 DOUBLE_CLASS_INIT_METHOD_SIGNATURE 707 ); 708 break; 709 case Type.BYTE: 710 cv.visitMethodInsn(INVOKESPECIAL, BYTE_CLASS_NAME, INIT_METHOD_NAME, BYTE_CLASS_INIT_METHOD_SIGNATURE); 711 break; 712 case Type.BOOLEAN: 713 cv.visitMethodInsn( 714 INVOKESPECIAL, 715 BOOLEAN_CLASS_NAME, 716 INIT_METHOD_NAME, 717 BOOLEAN_CLASS_INIT_METHOD_SIGNATURE 718 ); 719 break; 720 case Type.CHAR: 721 cv.visitMethodInsn( 722 INVOKESPECIAL, 723 CHARACTER_CLASS_NAME, 724 INIT_METHOD_NAME, 725 CHARACTER_CLASS_INIT_METHOD_SIGNATURE 726 ); 727 break; 728 } 729 } 730 731 739 public static void unwrapType(final MethodVisitor cv, final Type type) { 740 switch (type.getSort()) { 742 case Type.OBJECT: 743 String objectTypeName = type.getClassName().replace('.', '/'); 744 cv.visitTypeInsn(CHECKCAST, objectTypeName); 745 return; 746 case Type.ARRAY: 747 cv.visitTypeInsn(CHECKCAST, type.getDescriptor()); 748 return; 749 case Type.VOID: 750 return; 751 } 752 Label l0If = new Label(); 754 Label l1End = new Label(); 755 cv.visitInsn(DUP); 757 cv.visitJumpInsn(IFNONNULL, l0If); 758 cv.visitInsn(POP); 760 addDefaultValue(cv, type); 761 cv.visitJumpInsn(GOTO, l1End); 763 cv.visitLabel(l0If); 765 switch (type.getSort()) { 766 case Type.SHORT: 767 cv.visitTypeInsn(CHECKCAST, SHORT_CLASS_NAME); 768 cv.visitMethodInsn( 769 INVOKEVIRTUAL, 770 SHORT_CLASS_NAME, 771 SHORT_VALUE_METHOD_NAME, 772 SHORT_VALUE_METHOD_SIGNATURE 773 ); 774 break; 775 case Type.INT: 776 cv.visitTypeInsn(CHECKCAST, INTEGER_CLASS_NAME); 777 cv.visitMethodInsn( 778 INVOKEVIRTUAL, 779 INTEGER_CLASS_NAME, 780 INT_VALUE_METHOD_NAME, 781 INT_VALUE_METHOD_SIGNATURE 782 ); 783 break; 784 case Type.LONG: 785 cv.visitTypeInsn(CHECKCAST, LONG_CLASS_NAME); 786 cv.visitMethodInsn( 787 INVOKEVIRTUAL, LONG_CLASS_NAME, LONG_VALUE_METHOD_NAME, LONG_VALUE_METHOD_SIGNATURE 788 ); 789 break; 790 case Type.FLOAT: 791 cv.visitTypeInsn(CHECKCAST, FLOAT_CLASS_NAME); 792 cv.visitMethodInsn( 793 INVOKEVIRTUAL, 794 FLOAT_CLASS_NAME, 795 FLOAT_VALUE_METHOD_NAME, 796 FLOAT_VALUE_METHOD_SIGNATURE 797 ); 798 break; 799 case Type.DOUBLE: 800 cv.visitTypeInsn(CHECKCAST, DOUBLE_CLASS_NAME); 801 cv.visitMethodInsn( 802 INVOKEVIRTUAL, 803 DOUBLE_CLASS_NAME, 804 DOUBLE_VALUE_METHOD_NAME, 805 DOUBLE_VALUE_METHOD_SIGNATURE 806 ); 807 break; 808 case Type.BYTE: 809 cv.visitTypeInsn(CHECKCAST, BYTE_CLASS_NAME); 810 cv.visitMethodInsn( 811 INVOKEVIRTUAL, BYTE_CLASS_NAME, BYTE_VALUE_METHOD_NAME, BYTE_VALUE_METHOD_SIGNATURE 812 ); 813 break; 814 case Type.BOOLEAN: 815 cv.visitTypeInsn(CHECKCAST, BOOLEAN_CLASS_NAME); 816 cv.visitMethodInsn( 817 INVOKEVIRTUAL, 818 BOOLEAN_CLASS_NAME, 819 BOOLEAN_VALUE_METHOD_NAME, 820 BOOLEAN_VALUE_METHOD_SIGNATURE 821 ); 822 break; 823 case Type.CHAR: 824 cv.visitTypeInsn(CHECKCAST, CHARACTER_CLASS_NAME); 825 cv.visitMethodInsn( 826 INVOKEVIRTUAL, 827 CHARACTER_CLASS_NAME, 828 CHAR_VALUE_METHOD_NAME, 829 CHAR_VALUE_METHOD_SIGNATURE 830 ); 831 break; 832 } 833 cv.visitLabel(l1End); 834 } 835 836 842 public static void addDefaultValue(final MethodVisitor cv, final Type type) { 843 switch (type.getSort()) { 844 case Type.OBJECT: 845 cv.visitInsn(ACONST_NULL); 846 break; 847 case Type.ARRAY: 848 cv.visitInsn(ACONST_NULL); 849 break; 850 case Type.INT: 851 cv.visitInsn(ICONST_0); 852 break; 853 case Type.LONG: 854 cv.visitInsn(LCONST_0); 855 break; 856 case Type.SHORT: 857 cv.visitInsn(ICONST_0); 858 break; 859 case Type.FLOAT: 860 cv.visitInsn(FCONST_0); 861 break; 862 case Type.DOUBLE: 863 cv.visitInsn(DCONST_0); 864 break; 865 case Type.BYTE: 866 cv.visitInsn(ICONST_0); 867 break; 868 case Type.BOOLEAN: 869 cv.visitInsn(ICONST_0); 870 break; 871 case Type.CHAR: 872 cv.visitInsn(ICONST_0); 873 break; 874 } 875 } 876 877 883 public static void addNullableString(final MethodVisitor cv, final String value) { 884 if (value == null) { 885 cv.visitInsn(ACONST_NULL); 886 } else { 887 cv.visitLdcInsn(value); 888 } 889 } 890 891 897 public static int getRegisterDepth(final Type[] typesOnStack) { 898 int depth = 0; 899 for (int i = 0; i < typesOnStack.length; i++) { 900 Type type = typesOnStack[i]; 901 depth++; 902 switch (type.getSort()) { 903 case Type.LONG: 904 depth++; 905 break; 906 case Type.DOUBLE: 907 depth++; 908 break; 909 } 910 } 911 return depth; 912 } 913 914 921 public static int getRegisterIndexOf(final Type[] typesOnStack, final int typeIndex) { 922 int depth = 0; 923 for (int i = 0; i < typeIndex; i++) { 924 Type type = typesOnStack[i]; 925 depth++; 926 switch (type.getSort()) { 927 case Type.LONG: 928 depth++; 929 break; 930 case Type.DOUBLE: 931 depth++; 932 break; 933 } 934 } 935 return depth; 936 } 937 938 946 public static int getTypeIndexOf(final Type[] typesOnStack, final int registerIndex) { 947 for (int i = 0; i < typesOnStack.length; i++) { 948 int presumedRegisterIndex = getRegisterIndexOf(typesOnStack, i); 949 if (registerIndex == presumedRegisterIndex) { 950 return i; 951 } 952 } 953 return -1; 954 } 955 956 962 public static boolean isPrimitive(final Type returnType) { 963 if (returnType.getSort() == Type.INT || 964 returnType.getSort() == Type.SHORT || 965 returnType.getSort() == Type.LONG || 966 returnType.getSort() == Type.FLOAT || 967 returnType.getSort() == Type.DOUBLE || 968 returnType.getSort() == Type.BYTE || 969 returnType.getSort() == Type.CHAR || 970 returnType.getSort() == Type.BOOLEAN || 971 returnType.getSort() == Type.VOID) { 972 return true; 973 } else { 974 return false; 975 } 976 } 977 978 985 public static int incrementIndex(int index, final Type type) { 986 if (type.getSort() == Type.LONG || type.getSort() == Type.DOUBLE) { 987 index += 2; 988 } else { 989 index++; 990 } 991 return index; 992 } 993 994 1001 public static String getMethodDescriptor(final MethodInfo method) { 1002 ClassInfo[] parameters = method.getParameterTypes(); 1003 StringBuffer buf = new StringBuffer (); 1004 buf.append('('); 1005 for (int i = 0; i < parameters.length; ++i) { 1006 getClassDescriptor(buf, parameters[i]); 1007 } 1008 buf.append(')'); 1009 getClassDescriptor(buf, method.getReturnType()); 1010 return buf.toString(); 1011 } 1012 1013 1019 public static String getConstructorDescriptor(final ConstructorInfo constructor) { 1020 ClassInfo[] parameters = constructor.getParameterTypes(); 1021 StringBuffer buf = new StringBuffer (); 1022 buf.append('('); 1023 for (int i = 0; i < parameters.length; ++i) { 1024 getClassDescriptor(buf, parameters[i]); 1025 } 1026 buf.append(')'); 1027 getClassDescriptor(buf, VOID); 1028 return buf.toString(); 1029 } 1030 1031 1037 public static String getFieldDescriptor(final FieldInfo field) { 1038 return getClassDescriptor(field.getType()); 1039 } 1040 1041 1050 public static String getClassDescriptor(final ClassInfo c) { 1051 StringBuffer buf = new StringBuffer (); 1052 getClassDescriptor(buf, c); 1053 return buf.toString(); 1054 } 1055 1056 1063 private static void getClassDescriptor(final StringBuffer buf, final ClassInfo klass) { 1064 ClassInfo d = klass; 1065 while (true) { 1066 if (d.isPrimitive()) { 1067 char car; 1068 if (d.equals(INTEGER)) { 1069 car = 'I'; 1070 } else if (d.equals(VOID)) { 1071 car = 'V'; 1072 } else if (d.equals(BOOLEAN)) { 1073 car = 'Z'; 1074 } else if (d.equals(BYTE)) { 1075 car = 'B'; 1076 } else if (d.equals(CHARACTER)) { 1077 car = 'C'; 1078 } else if (d.equals(SHORT)) { 1079 car = 'S'; 1080 } else if (d.equals(DOUBLE)) { 1081 car = 'D'; 1082 } else if (d.equals(FLOAT)) { 1083 car = 'F'; 1084 } else if (d.equals(LONG)) { 1085 car = 'J'; 1086 } else { 1087 throw new Error ("should not happen"); 1088 } 1089 buf.append(car); 1090 return; 1091 } else if (d.isArray()) { 1092 buf.append('['); 1093 d = d.getComponentType(); 1094 } else { 1095 buf.append('L'); 1096 String name = d.getName(); 1097 int len = name.length(); 1098 for (int i = 0; i < len; ++i) { 1099 char car = name.charAt(i); 1100 buf.append(car == '.' ? '/' : car); 1101 } 1102 buf.append(';'); 1103 return; 1104 } 1105 } 1106 } 1107 1108 1117 public static Type[] getArgumentTypes(final MethodInfo method) { 1118 ClassInfo[] classes = method.getParameterTypes(); 1119 Type[] types = new Type[classes.length]; 1120 for (int i = classes.length - 1; i >= 0; --i) { 1121 types[i] = getType(classes[i]); 1122 } 1123 return types; 1124 } 1125 1126 1133 public static Type getType(final ClassInfo c) { 1134 if (c.isPrimitive()) { 1135 if (c.equals(INTEGER)) { 1136 return Type.INT_TYPE; 1137 } else if (c.equals(VOID)) { 1138 return Type.VOID_TYPE; 1139 } else if (c.equals(BOOLEAN)) { 1140 return Type.BOOLEAN_TYPE; 1141 } else if (c.equals(BYTE)) { 1142 return Type.BYTE_TYPE; 1143 } else if (c.equals(CHARACTER)) { 1144 return Type.CHAR_TYPE; 1145 } else if (c.equals(SHORT)) { 1146 return Type.SHORT_TYPE; 1147 } else if (c.equals(DOUBLE)) { 1148 return Type.DOUBLE_TYPE; 1149 } else if (c.equals(FLOAT)) { 1150 return Type.FLOAT_TYPE; 1151 } else if (c.equals(LONG)) { 1152 return Type.LONG_TYPE; 1153 } else { 1154 throw new Error ("should not happen"); 1155 } 1156 } else { 1157 return Type.getType(getClassDescriptor(c)); 1158 } 1159 } 1160} | Popular Tags |