From 841d0a104b3a97a793ea26eb454f2c16eeb130a7 Mon Sep 17 00:00:00 2001 From: maohui1993 <501206021@qq.com> Date: Tue, 10 May 2016 11:01:28 +0800 Subject: [PATCH 1/2] Update ConstructorAccess.java Add a cache for avoiding to load same class --- .../reflectasm/ConstructorAccess.java | 120 ++++++++++-------- 1 file changed, 70 insertions(+), 50 deletions(-) diff --git a/src/com/esotericsoftware/reflectasm/ConstructorAccess.java b/src/com/esotericsoftware/reflectasm/ConstructorAccess.java index 6364462..adadaec 100644 --- a/src/com/esotericsoftware/reflectasm/ConstructorAccess.java +++ b/src/com/esotericsoftware/reflectasm/ConstructorAccess.java @@ -16,13 +16,19 @@ import static org.objectweb.asm.Opcodes.*; +import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; public abstract class ConstructorAccess { + private static Map> cacheMap = new HashMap>(); + private static int cacheSize = 50; boolean isNonStaticMemberClass; public boolean isNonStaticMemberClass () { @@ -50,59 +56,73 @@ static public ConstructorAccess get (Class type) { if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName; Class accessClass; - AccessClassLoader loader = AccessClassLoader.get(type); - try { - accessClass = loader.loadClass(accessClassName); - } catch (ClassNotFoundException ignored) { - synchronized (loader) { - try { - accessClass = loader.loadClass(accessClassName); - } catch (ClassNotFoundException ignored2) { - String accessClassNameInternal = accessClassName.replace('.', '/'); - String classNameInternal = className.replace('.', '/'); - String enclosingClassNameInternal; - Constructor constructor = null; - int modifiers = 0; - if (!isNonStaticMemberClass) { - enclosingClassNameInternal = null; - try { - constructor = type.getDeclaredConstructor((Class[])null); - modifiers = constructor.getModifiers(); - } catch (Exception ex) { - throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName(), ex); - } - if (Modifier.isPrivate(modifiers)) { - throw new RuntimeException("Class cannot be created (the no-arg constructor is private): " + type.getName()); - } - } else { - enclosingClassNameInternal = enclosingType.getName().replace('.', '/'); - try { - constructor = type.getDeclaredConstructor(enclosingType); // Inner classes should have this. - modifiers = constructor.getModifiers(); - } catch (Exception ex) { - throw new RuntimeException("Non-static member class cannot be created (missing enclosing class constructor): " - + type.getName(), ex); - } - if (Modifier.isPrivate(modifiers)) { - throw new RuntimeException( - "Non-static member class cannot be created (the enclosing class constructor is private): " + type.getName()); + if(cacheMap.containsKey(accessClassName)) { + accessClass = cacheMap.get(accessClassName).get(); + } else { + AccessClassLoader loader = AccessClassLoader.get(type); + try { + accessClass = loader.loadClass(accessClassName); + } catch (ClassNotFoundException ignored) { + synchronized (loader) { + try { + accessClass = loader.loadClass(accessClassName); + } catch (ClassNotFoundException ignored2) { + String accessClassNameInternal = accessClassName.replace('.', '/'); + String classNameInternal = className.replace('.', '/'); + String enclosingClassNameInternal; + Constructor constructor = null; + int modifiers = 0; + if (!isNonStaticMemberClass) { + enclosingClassNameInternal = null; + try { + constructor = type.getDeclaredConstructor((Class[]) null); + modifiers = constructor.getModifiers(); + } catch (Exception ex) { + throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName(), ex); + } + if (Modifier.isPrivate(modifiers)) { + throw new RuntimeException("Class cannot be created (the no-arg constructor is private): " + type.getName()); + } + } else { + enclosingClassNameInternal = enclosingType.getName().replace('.', '/'); + try { + constructor = type.getDeclaredConstructor(enclosingType); // Inner classes should have this. + modifiers = constructor.getModifiers(); + } catch (Exception ex) { + throw new RuntimeException("Non-static member class cannot be created (missing enclosing class constructor): " + + type.getName(), ex); + } + if (Modifier.isPrivate(modifiers)) { + throw new RuntimeException( + "Non-static member class cannot be created (the enclosing class constructor is private): " + type.getName()); + } } - } - String superclassNameInternal = Modifier.isPublic(modifiers) ? - "com/esotericsoftware/reflectasm/PublicConstructorAccess" : - "com/esotericsoftware/reflectasm/ConstructorAccess"; + String superclassNameInternal = Modifier.isPublic(modifiers) ? + "com/esotericsoftware/reflectasm/PublicConstructorAccess" : + "com/esotericsoftware/reflectasm/ConstructorAccess"; - ClassWriter cw = new ClassWriter(0); - cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, superclassNameInternal, null); + ClassWriter cw = new ClassWriter(0); + cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, superclassNameInternal, null); - insertConstructor(cw, superclassNameInternal); - insertNewInstance(cw, classNameInternal); - insertNewInstanceInner(cw, classNameInternal, enclosingClassNameInternal); + insertConstructor(cw, superclassNameInternal); + insertNewInstance(cw, classNameInternal); + insertNewInstanceInner(cw, classNameInternal, enclosingClassNameInternal); - cw.visitEnd(); - accessClass = loader.defineClass(accessClassName, cw.toByteArray()); + cw.visitEnd(); + accessClass = loader.defineClass(accessClassName, cw.toByteArray()); + } + } + } + if(cacheMap.size() > cacheSize) { + Iterator it = cacheMap.entrySet().iterator(); + while(it.hasNext()) { + it.remove(); + if(cacheMap.size() < cacheSize/2) { + break; + } } } + cacheMap.put(accessClassName, new WeakReference(accessClass)); } ConstructorAccess access; try { @@ -115,9 +135,9 @@ static public ConstructorAccess get (Class type) { // Throw a Runtime exception here instead of an IllegalAccessError when invoking newInstance() throw new RuntimeException( (!isNonStaticMemberClass ? - "Class cannot be created (the no-arg constructor is protected or package-protected, and its ConstructorAccess could not be defined in the same class loader): " : - "Non-static member class cannot be created (the enclosing class constructor is protected or package-protected, and its ConstructorAccess could not be defined in the same class loader): ") - + type.getName()); + "Class cannot be created (the no-arg constructor is protected or package-protected, and its ConstructorAccess could not be defined in the same class loader): " : + "Non-static member class cannot be created (the enclosing class constructor is protected or package-protected, and its ConstructorAccess could not be defined in the same class loader): ") + + type.getName()); } access.isNonStaticMemberClass = isNonStaticMemberClass; return access; From 5f07a578c946cda9cc7dc3bd97e0ddf2574ffc7b Mon Sep 17 00:00:00 2001 From: maohui1993 <501206021@qq.com> Date: Tue, 10 May 2016 14:32:27 +0800 Subject: [PATCH 2/2] Update ConstructorAccess.java --- .../reflectasm/ConstructorAccess.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/com/esotericsoftware/reflectasm/ConstructorAccess.java b/src/com/esotericsoftware/reflectasm/ConstructorAccess.java index adadaec..7cf5c06 100644 --- a/src/com/esotericsoftware/reflectasm/ConstructorAccess.java +++ b/src/com/esotericsoftware/reflectasm/ConstructorAccess.java @@ -113,17 +113,22 @@ static public ConstructorAccess get (Class type) { } } } - if(cacheMap.size() > cacheSize) { - Iterator it = cacheMap.entrySet().iterator(); - while(it.hasNext()) { - it.remove(); - if(cacheMap.size() < cacheSize/2) { - break; + if (cacheMap.size() > cacheSize) { + synchronized (cacheMap) { + Iterator it = cacheMap.entrySet().iterator(); + while (it.hasNext()) { + it.remove(); + if (cacheMap.size() < cacheSize / 2) { + break; + } } } } - cacheMap.put(accessClassName, new WeakReference(accessClass)); + synchronized (cacheMap) { + cacheMap.put(accessClassName, new WeakReference(accessClass)); + } } + ConstructorAccess access; try { access = (ConstructorAccess)accessClass.newInstance();