1 4 package com.tc.aspectwerkz.reflect.impl.asm; 5 6 7 import com.tc.backport175.bytecode.AnnotationElement; 8 import com.tc.backport175.bytecode.AnnotationReader; 9 import com.tc.asm.*; 10 11 import com.tc.aspectwerkz.exception.WrappedRuntimeException; 12 import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo; 13 import com.tc.aspectwerkz.reflect.ClassInfo; 14 import com.tc.aspectwerkz.reflect.StaticInitializationInfo; 15 import com.tc.aspectwerkz.reflect.ConstructorInfo; 16 import com.tc.aspectwerkz.reflect.MethodInfo; 17 import com.tc.aspectwerkz.reflect.StaticInitializationInfoImpl; 18 import com.tc.aspectwerkz.reflect.FieldInfo; 19 import com.tc.aspectwerkz.transform.TransformationConstants; 20 import com.tc.aspectwerkz.transform.inlining.AsmHelper; 21 import com.tc.aspectwerkz.transform.inlining.AsmNullAdapter; 22 import com.tc.aspectwerkz.util.ContextClassLoader; 23 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.lang.ref.WeakReference ; 27 import java.lang.reflect.Array ; 28 import java.lang.reflect.Modifier ; 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 import java.util.List ; 32 33 44 public class AsmClassInfo implements ClassInfo { 45 46 protected final static String [] EMPTY_STRING_ARRAY = new String [0]; 47 48 protected final static List EMPTY_LIST = new ArrayList (); 49 50 53 private final WeakReference m_loaderRef; 54 55 58 private String m_name; 59 60 63 private String m_signature; 64 65 68 private String m_genericsSignature; 69 70 73 private int m_modifiers; 74 75 78 private boolean m_isInterface = false; 79 80 83 private boolean m_isPrimitive = false; 84 85 88 private boolean m_isArray = false; 89 90 93 private boolean m_hasStaticInitializer = false; 94 95 98 private StaticInitializationInfo m_staticInitializer = null; 99 100 105 private final HashMap m_constructors = new HashMap (); 106 private ArrayList m_sortedConstructorHashes = new ArrayList (); 107 private ConstructorInfo[] m_constructorsLazy = null; 108 109 110 115 private final HashMap m_methods = new HashMap (); 116 private ArrayList m_sortedMethodHashes = new ArrayList (); 117 private MethodInfo[] m_methodsLazy = null; 118 119 124 private final HashMap m_fields = new HashMap (); 125 private ArrayList m_sortedFieldHashes = new ArrayList (); 126 private FieldInfo[] m_fieldsLazy = null; 127 128 131 private String [] m_interfaceClassNames = null; 132 133 136 private ClassInfo[] m_interfaces = null; 137 138 141 private String m_superClassName = null; 142 143 146 private ClassInfo m_superClass = null; 147 148 152 private AnnotationReader m_annotationReader = null; 153 154 157 private String m_componentTypeName = null; 158 159 162 private ClassInfo m_componentType = null; 163 164 167 private final AsmClassInfoRepository m_classInfoRepository; 168 169 175 AsmClassInfo(final byte[] bytecode, final ClassLoader loader) { 176 if (bytecode == null) { 177 throw new IllegalArgumentException ("bytecode can not be null"); 178 } 179 m_loaderRef = new WeakReference (loader); 180 m_classInfoRepository = AsmClassInfoRepository.getRepository(loader); 181 try { 182 ClassReader cr = new ClassReader(bytecode); 183 ClassInfoClassAdapter visitor = new ClassInfoClassAdapter(); 184 cr.accept(visitor, false); 185 } catch (Throwable t) { 186 t.printStackTrace(); 187 } 188 m_classInfoRepository.addClassInfo(this); 189 } 190 191 197 AsmClassInfo(final InputStream resourceStream, final ClassLoader loader) { 198 if (resourceStream == null) { 199 throw new IllegalArgumentException ("resource stream can not be null"); 200 } 201 m_loaderRef = new WeakReference (loader); 202 m_classInfoRepository = AsmClassInfoRepository.getRepository(loader); 203 try { 204 ClassReader cr = new ClassReader(resourceStream); 205 ClassInfoClassAdapter visitor = new ClassInfoClassAdapter(); 206 cr.accept(visitor, false); 207 } catch (Throwable t) { 208 t.printStackTrace(); 209 } 210 m_classInfoRepository.addClassInfo(this); 211 } 212 213 222 AsmClassInfo(final String className, 223 final ClassLoader loader, 224 final ClassInfo componentInfo) { 225 m_loaderRef = new WeakReference (loader); 226 m_name = className.replace('/', '.'); 227 m_classInfoRepository = AsmClassInfoRepository.getRepository(loader); 228 m_isArray = true; 229 m_componentType = componentInfo; 230 m_componentTypeName = componentInfo.getName(); 231 m_modifiers = componentInfo.getModifiers() | Modifier.ABSTRACT | Modifier.FINAL; 232 m_isInterface = false; m_superClass = JavaClassInfo.getClassInfo(Object .class); 234 m_superClassName = m_superClass.getName(); 235 m_interfaceClassNames = new String [0]; 236 m_interfaces = new ClassInfo[0]; 237 m_signature = AsmHelper.getClassDescriptor(this); 238 m_classInfoRepository.addClassInfo(this); 239 } 240 241 248 public static ClassInfo newClassInfo(final byte[] bytecode, final ClassLoader loader) { 249 final String className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode); 250 AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader); 251 repository.removeClassInfo(className); 252 return new AsmClassInfo(bytecode, loader); 253 } 254 255 262 public static ClassInfo getClassInfo(final String className, final ClassLoader loader) { 263 final String javaClassName = getJavaClassName(className); 264 AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader); 265 ClassInfo classInfo = repository.getClassInfo(javaClassName); 266 if (classInfo == null) { 267 classInfo = createClassInfoFromStream(javaClassName, loader); 268 } 269 return classInfo; 270 } 271 272 279 public static ClassInfo getClassInfo(final byte[] bytecode, final ClassLoader loader) { 280 final String className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode); 281 AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader); 282 ClassInfo classInfo = repository.getClassInfo(className); 283 if (classInfo == null) { 284 classInfo = new AsmClassInfo(bytecode, loader); 285 } 286 return classInfo; 287 } 288 289 297 public static ClassInfo getClassInfo(final String className, final byte[] bytecode, final ClassLoader loader) { 298 AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader); 299 ClassInfo classInfo = repository.getClassInfo(className.replace('.', '/')); 300 if (classInfo == null) { 301 classInfo = new AsmClassInfo(bytecode, loader); 302 } 303 return classInfo; 304 } 305 306 313 public static ClassInfo getClassInfo(final String name, final InputStream stream, final ClassLoader loader) { 314 try { 315 ClassReader cr = new ClassReader(stream); 316 byte[] bytes = cr.b; 318 ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter(); 319 cr.accept(visitor, true); 320 final String className = visitor.getClassName(); 321 AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader); 322 ClassInfo classInfo = repository.getClassInfo(className); 323 if (classInfo == null) { 324 classInfo = new AsmClassInfo(bytes, loader); 325 } 326 return classInfo; 327 } catch (IOException e) { 328 throw new WrappedRuntimeException("Can't get ClassInfo for "+name, e); 329 } 330 } 331 332 337 public static void markDirty(final String className, final ClassLoader loader) { 338 AsmClassInfoRepository.getRepository(loader).removeClassInfo(className); 339 } 340 341 347 public static String retrieveClassNameFromBytecode(final byte[] bytecode) { 348 ClassReader cr = new ClassReader(bytecode); 349 ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter(); 350 cr.accept(visitor, true); 351 return visitor.getClassName(); 352 } 353 354 360 public static Class getPrimitiveClass(final String className) { 361 if (className.equals("void")) { 362 return void.class; 363 } else if (className.equals("long")) { 364 return long.class; 365 } else if (className.equals("int")) { 366 return int.class; 367 } else if (className.equals("short")) { 368 return short.class; 369 } else if (className.equals("double")) { 370 return double.class; 371 } else if (className.equals("float")) { 372 return float.class; 373 } else if (className.equals("byte")) { 374 return byte.class; 375 } else if (className.equals("boolean")) { 376 return boolean.class; 377 } else if (className.equals("char")) { 378 return char.class; 379 } else { 380 return null; 381 } 382 } 383 384 389 public AnnotationElement.Annotation[] getAnnotations() { 390 return getAnnotationReader().getAnnotationElements(); 391 } 392 393 398 public String getName() { 399 return m_name; 400 } 401 402 407 public String getSignature() { 408 return m_signature; 409 } 410 411 416 public String getGenericsSignature() { 417 return m_genericsSignature; 418 } 419 420 425 public int getModifiers() { 426 return m_modifiers; 427 } 428 429 434 public ClassLoader getClassLoader() { 435 return (ClassLoader ) m_loaderRef.get(); 436 } 437 438 443 public boolean hasStaticInitializer() { 444 return m_hasStaticInitializer; 445 } 446 447 452 public StaticInitializationInfo staticInitializer() { 453 if (hasStaticInitializer() && m_staticInitializer == null) { 454 m_staticInitializer = new StaticInitializationInfoImpl(this); 455 } 456 return m_staticInitializer; 457 } 458 459 465 public ConstructorInfo getConstructor(final int hash) { 466 ConstructorInfo constructor = (ConstructorInfo) m_constructors.get(new Integer (hash)); 467 if (constructor == null && getSuperclass() != null) { 468 constructor = getSuperclass().getConstructor(hash); 469 } 470 return constructor; 471 } 472 473 478 public synchronized ConstructorInfo[] getConstructors() { 479 if (m_constructorsLazy == null) { 480 ConstructorInfo[] constructorInfos = new ConstructorInfo[m_sortedConstructorHashes.size()]; 481 for (int i = 0; i < m_sortedConstructorHashes.size(); i++) { 482 constructorInfos[i] = (ConstructorInfo) m_constructors.get(m_sortedConstructorHashes.get(i)); 483 } 484 m_constructorsLazy = constructorInfos; 485 } 486 return m_constructorsLazy; 487 } 488 489 495 public MethodInfo getMethod(final int hash) { 496 MethodInfo method = (MethodInfo) m_methods.get(new Integer (hash)); 497 if (method == null) { 498 for (int i = 0; i < getInterfaces().length; i++) { 499 method = getInterfaces()[i].getMethod(hash); 500 if (method != null) { 501 break; 502 } 503 } 504 } 505 if (method == null && getSuperclass() != null) { 506 method = getSuperclass().getMethod(hash); 507 } 508 return method; 509 } 510 511 516 public synchronized MethodInfo[] getMethods() { 517 if (m_methodsLazy == null) { 518 MethodInfo[] methodInfos = new MethodInfo[m_sortedMethodHashes.size()]; 519 for (int i = 0; i < m_sortedMethodHashes.size(); i++) { 520 methodInfos[i] = (MethodInfo) m_methods.get(m_sortedMethodHashes.get(i)); 521 } 522 m_methodsLazy = methodInfos; 523 } 524 return m_methodsLazy; 525 } 526 527 533 public FieldInfo getField(final int hash) { 534 FieldInfo field = (FieldInfo) m_fields.get(new Integer (hash)); 535 if (field == null && getSuperclass() != null) { 536 field = getSuperclass().getField(hash); 537 } 538 if (field == null) { 539 ClassInfo[] interfaces = getInterfaces(); 541 for (int i = 0; i < interfaces.length; i++) { 542 ClassInfo ifc = interfaces[i]; 543 field = ifc.getField(hash); 544 if (field != null) 545 break; 546 } 547 } 548 return field; 549 } 550 551 556 public FieldInfo[] getFields() { 557 if (m_fieldsLazy == null) { 558 FieldInfo[] fieldInfos = new FieldInfo[m_sortedFieldHashes.size()]; 559 for (int i = 0; i < m_sortedFieldHashes.size(); i++) { 560 fieldInfos[i] = (FieldInfo) m_fields.get(m_sortedFieldHashes.get(i)); 561 } 562 m_fieldsLazy = fieldInfos; 563 } 564 return m_fieldsLazy; 565 } 566 567 572 public synchronized ClassInfo[] getInterfaces() { 573 if (m_interfaces == null) { 574 m_interfaces = new ClassInfo[m_interfaceClassNames.length]; 575 for (int i = 0; i < m_interfaceClassNames.length; i++) { 576 m_interfaces[i] = AsmClassInfo.getClassInfo(m_interfaceClassNames[i], (ClassLoader ) m_loaderRef.get()); 577 } 578 } 579 return m_interfaces; 580 } 581 582 587 public ClassInfo getSuperclass() { 588 if (m_superClass == null && m_superClassName != null) { 589 m_superClass = AsmClassInfo.getClassInfo(m_superClassName, (ClassLoader ) m_loaderRef.get()); 590 } 591 return m_superClass; 592 } 593 594 599 public ClassInfo getComponentType() { 600 if (isArray() && (m_componentTypeName == null)) { 601 m_componentType = AsmClassInfo.getClassInfo(m_componentTypeName, (ClassLoader ) m_loaderRef.get()); 602 } 603 return m_componentType; 604 } 605 606 611 public boolean isInterface() { 612 return m_isInterface; 613 } 614 615 620 public boolean isPrimitive() { 621 return m_isPrimitive; 622 } 623 624 629 public boolean isArray() { 630 return m_isArray; 631 } 632 633 636 public boolean equals(Object o) { 637 if (this == o) { 638 return true; 639 } 640 if (!(o instanceof ClassInfo)) { 641 return false; 642 } 643 ClassInfo classInfo = (ClassInfo) o; 644 return m_name.equals(classInfo.getName()); 645 } 646 647 650 public int hashCode() { 651 return m_name.hashCode(); 652 } 653 654 public String toString() { 655 return m_name; 656 } 657 658 666 public static ClassInfo getArrayClassInfo(final String className, 667 final ClassLoader loader, 668 final ClassInfo componentClassInfo) { 669 return new AsmClassInfo(className, loader, componentClassInfo); 670 } 671 672 679 private static ClassInfo createClassInfoFromStream(final String name, 680 final ClassLoader loader) { 681 final String className = name.replace('.', '/'); 682 683 if (name.indexOf('/') < 0) { 685 int dimension = 0; 688 for (int i = className.indexOf('['); i > 0; i = className.indexOf('[', i + 1)) { 689 dimension++; 690 } 691 String unidimComponentName = className; 692 if (dimension > 0) { 693 int unidimComponentTypeIndex = className.indexOf('['); 694 unidimComponentName = className.substring(0, unidimComponentTypeIndex); 695 } 696 Class primitiveClass = AsmClassInfo.getPrimitiveClass(unidimComponentName); 697 if (primitiveClass != null && primitiveClass.isPrimitive()) { 698 if (dimension == 0) { 699 return JavaClassInfo.getClassInfo(primitiveClass); 700 } else { 701 Class arrayClass = Array.newInstance(primitiveClass, new int[dimension]).getClass(); 702 return JavaClassInfo.getClassInfo(arrayClass); 703 } 704 } 705 } 706 707 int componentTypeIndex = className.lastIndexOf('['); 710 String componentName = className; 711 boolean isArray = false; 712 if (componentTypeIndex > 0) { 713 componentName = className.substring(0, componentTypeIndex); 714 isArray = true; 715 } 716 717 ClassInfo componentInfo = null; 718 719 if (componentName.indexOf('[') > 0) { 721 componentInfo = getClassInfo(componentName, loader); 722 } else { 723 InputStream componentClassAsStream = null; 724 if (loader != null) { 725 componentClassAsStream = loader.getResourceAsStream(componentName + ".class"); 726 } else { 727 componentClassAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream( 729 componentName + ".class"); 730 } 731 if (componentClassAsStream == null) { 732 if (componentName.indexOf('[') > 0) { 734 return getClassInfo(componentName, loader); 735 } 736 System.out.println( 737 "AW::WARNING - could not load class [" 738 + componentName 739 + "] as a resource in loader [" 740 + loader 741 + "]" 742 ); 743 componentInfo = new ClassInfo.NullClassInfo(); 744 } 745 try { 746 componentInfo = AsmClassInfo.getClassInfo(componentName, componentClassAsStream, loader); 747 } finally { 748 try { 749 componentClassAsStream.close(); 750 } catch (Exception e) { 751 } 753 } 754 } 755 756 if (!isArray) { 757 return componentInfo; 758 } else { 759 return AsmClassInfo.getArrayClassInfo(className, loader, componentInfo); 760 } 761 } 762 763 787 792 public static class ClassNameRetrievalClassAdapter extends AsmNullAdapter.NullClassAdapter { 793 794 private String m_className; 795 796 public void visit(final int version, 797 final int access, 798 final String name, 799 final String desc, 800 final String superName, 801 final String [] interfaces) { 802 m_className = name.replace('/', '.'); 803 } 804 805 public String getClassName() { 806 return m_className; 807 } 808 } 809 810 815 private class ClassInfoClassAdapter extends AsmNullAdapter.NullClassAdapter { 816 817 public void visit(final int version, 818 final int access, 819 final String name, 820 final String signature, 821 final String superName, 822 final String [] interfaces) { 823 824 m_modifiers = access; 825 m_name = name.replace('/', '.'); 826 m_genericsSignature = signature; 827 m_isInterface = Modifier.isInterface(m_modifiers); 828 m_superClassName = superName == null ? null : superName.replace('/', '.'); 830 m_interfaceClassNames = new String [interfaces.length]; 831 for (int i = 0; i < interfaces.length; i++) { 832 m_interfaceClassNames[i] = interfaces[i].replace('/', '.'); 833 } 834 if (m_name.endsWith("[]")) { 838 m_isArray = true; 839 int index = m_name.indexOf('['); 840 m_componentTypeName = m_name.substring(0, index); 841 } else if (m_name.equals("long") 842 || m_name.equals("int") 843 || m_name.equals("short") 844 || m_name.equals("double") 845 || m_name.equals("float") 846 || m_name.equals("byte") 847 || m_name.equals("boolean") 848 || m_name.equals("char")) { 849 m_isPrimitive = true; 850 } 851 } 852 853 public FieldVisitor visitField(final int access, 854 final String name, 855 final String desc, 856 final String signature, 857 final Object value) { 858 final FieldStruct struct = new FieldStruct(); 859 struct.modifiers = access; 860 struct.name = name; 861 struct.desc = desc; 862 struct.signature = signature; 863 struct.value = value; 864 AsmFieldInfo fieldInfo = new AsmFieldInfo(struct, m_name, (ClassLoader ) m_loaderRef.get()); 865 Integer hash = new Integer (AsmHelper.calculateFieldHash(name, desc)); 866 m_fields.put(hash, fieldInfo); 867 m_sortedFieldHashes.add(hash); 868 return AsmNullAdapter.NullFieldAdapter.NULL_FIELD_ADAPTER; 869 } 870 871 public MethodVisitor visitMethod(final int access, 872 final String name, 873 final String desc, 874 final String signature, 875 final String [] exceptions) { 876 final MethodStruct struct = new MethodStruct(); 877 struct.modifiers = access; 878 struct.name = name; 879 struct.desc = desc; 880 struct.signature = signature; 881 struct.exceptions = exceptions; 882 Integer hash = new Integer (AsmHelper.calculateMethodHash(name, desc)); 883 AsmMethodInfo methodInfo = null; 885 if (name.equals(TransformationConstants.CLINIT_METHOD_NAME)) { 886 m_hasStaticInitializer = true; 887 } else { 888 AsmMemberInfo memberInfo = null; 889 if (name.equals(TransformationConstants.INIT_METHOD_NAME)) { 890 memberInfo = new AsmConstructorInfo(struct, m_name, (ClassLoader ) m_loaderRef.get()); 891 m_constructors.put(hash, memberInfo); 892 m_sortedConstructorHashes.add(hash); 893 } else { 894 memberInfo = new AsmMethodInfo(struct, m_name, (ClassLoader ) m_loaderRef.get()); 895 m_methods.put(hash, memberInfo); 896 m_sortedMethodHashes.add(hash); 897 methodInfo = (AsmMethodInfo) memberInfo; 898 } 899 } 900 if (methodInfo != null) { 901 Type[] parameterTypes = Type.getArgumentTypes(desc); 904 if (parameterTypes.length > 0) { 905 MethodVisitor methodParameterNamesVisitor = new MethodParameterNamesCodeAdapter( 906 Modifier.isStatic(access), 907 parameterTypes.length, methodInfo 908 ); 909 return methodParameterNamesVisitor; 910 } else { 911 methodInfo.m_parameterNames = EMPTY_STRING_ARRAY; 912 } 913 } 914 return AsmNullAdapter.NullMethodAdapter.NULL_METHOD_ADAPTER; 915 } 916 917 public void visitEnd() { 918 m_signature = AsmHelper.getClassDescriptor(AsmClassInfo.this); 919 } 920 } 921 922 927 static class MethodParameterNamesCodeAdapter extends AsmNullAdapter.NullMethodAdapter { 928 private final boolean m_isStatic; 929 private final int m_parameterCount; 930 private AsmMethodInfo m_methodInfo; 931 private int m_signatureParameterRegisterDepth = 0; 932 933 public MethodParameterNamesCodeAdapter(boolean isStatic, int parameterCount, AsmMethodInfo methodInfo) { 934 m_isStatic = isStatic; 935 m_parameterCount = parameterCount; 936 m_methodInfo = methodInfo; 937 m_methodInfo.m_parameterNames = new String [m_parameterCount]; 938 939 if (!m_isStatic) { 943 m_signatureParameterRegisterDepth++; } 945 m_signatureParameterRegisterDepth += AsmHelper.getRegisterDepth( 946 Type.getArgumentTypes(m_methodInfo.m_member.desc) 947 ); 948 } 949 950 961 public void visitLocalVariable(String name, String desc, String sig, Label start, Label end, int index) { 962 if (index < m_signatureParameterRegisterDepth) { 963 if (index == 0) { 965 if (!m_isStatic) { 966 } else { 968 m_methodInfo.pushParameterNameFromRegister(index, name); 969 } 970 } else { 971 m_methodInfo.pushParameterNameFromRegister(index, name); 972 } 973 } else { 974 } 976 } 977 } 978 979 985 private static String getJavaClassName(final String className) { 986 String javaClassName; 987 if (className.startsWith("[")) { 988 javaClassName = Type.getType(className).getClassName(); 989 } else { 990 javaClassName = className.replace('/', '.'); 991 } 992 return javaClassName; 993 } 994 995 1000 public AnnotationReader getAnnotationReader() { 1001 if (m_annotationReader == null) { 1002 ClassLoader loader = ContextClassLoader.getLoaderOrSystemLoader((ClassLoader ) m_loaderRef.get()); 1003 m_annotationReader = AnnotationReader.getReaderFor(m_name, loader); 1004 } 1005 return m_annotationReader; 1006 } 1007} | Popular Tags |