diff --git a/springloaded/src/main/java/org/springsource/loaded/GlobalConfiguration.java b/springloaded/src/main/java/org/springsource/loaded/GlobalConfiguration.java index 13feab6..fcba3c1 100644 --- a/springloaded/src/main/java/org/springsource/loaded/GlobalConfiguration.java +++ b/springloaded/src/main/java/org/springsource/loaded/GlobalConfiguration.java @@ -86,6 +86,9 @@ public class GlobalConfiguration { * Determine whether on disk caching will be used. */ public static boolean isCaching = false; + + public static boolean investigateSystemClassReflection = false; + public static boolean rewriteAllSystemClasses = false; /** * A well known profile (e.g. grails) can tweak a lot of the default options in a particular way. @@ -286,6 +289,12 @@ public class GlobalConfiguration { verboseMode = true; reloadMessages = true; } + else if (kv.equals("investigateSystemClassReflection")) { + investigateSystemClassReflection = true; + } + else if (kv.equals("rewriteAllSystemClasses")) { + rewriteAllSystemClasses = true; + } else if (kv.equals("asserts")) { Log.log("[asserts mode on] Will verify system coherence"); assertsMode = true; diff --git a/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java b/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java index c4be72b..1397154 100644 --- a/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java +++ b/springloaded/src/main/java/org/springsource/loaded/SystemClassReflectionInvestigator.java @@ -31,9 +31,10 @@ import org.objectweb.asm.Opcodes; */ public class SystemClassReflectionInvestigator { - public static int investigate(String slashedClassName, byte[] bytes) { + + public static int investigate(String slashedClassName, byte[] bytes, boolean print) { ClassReader fileReader = new ClassReader(bytes); - RewriteClassAdaptor classAdaptor = new RewriteClassAdaptor(); + RewriteClassAdaptor classAdaptor = new RewriteClassAdaptor(print); fileReader.accept(classAdaptor, ClassReader.SKIP_FRAMES); return classAdaptor.hitCount; } @@ -43,15 +44,17 @@ public class SystemClassReflectionInvestigator { int hitCount = 0; private ClassWriter cw; int bits = 0x0000; + private boolean print; private String classname; private static boolean isInterceptable(String owner, String methodName) { return MethodInvokerRewriter.RewriteClassAdaptor.intercepted.contains(owner + "." + methodName); } - public RewriteClassAdaptor() { + public RewriteClassAdaptor(boolean print) { // TODO should it also compute frames? super(ASM5,new ClassWriter(ClassWriter.COMPUTE_MAXS)); + this.print = print; cw = (ClassWriter) cv; } @@ -85,7 +88,9 @@ public class SystemClassReflectionInvestigator { private boolean interceptReflection(String owner, String name, String desc) { if (isInterceptable(owner, name)) { hitCount++; - System.out.println("SystemClassReflectionInvestigator: " + classname + " uses " + owner + "." + name + desc); + if (print) { + System.out.println("SystemClassReflectionInvestigator: " + classname + " uses " + owner + "." + name + desc); + } } return false; } diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/SpringLoadedPreProcessor.java b/springloaded/src/main/java/org/springsource/loaded/agent/SpringLoadedPreProcessor.java index 2f64011..46fc820 100644 --- a/springloaded/src/main/java/org/springsource/loaded/agent/SpringLoadedPreProcessor.java +++ b/springloaded/src/main/java/org/springsource/loaded/agent/SpringLoadedPreProcessor.java @@ -36,6 +36,7 @@ import org.springsource.loaded.LoadtimeInstrumentationPlugin; import org.springsource.loaded.Log; import org.springsource.loaded.Plugin; import org.springsource.loaded.ReloadableType; +import org.springsource.loaded.SystemClassReflectionInvestigator; import org.springsource.loaded.SystemClassReflectionRewriter; import org.springsource.loaded.TypeRegistry; import org.springsource.loaded.Utils; @@ -147,21 +148,25 @@ public class SpringLoadedPreProcessor implements Constants { } catch (Exception re) { re.printStackTrace(); } - // This block can help when you suspect there is a system class using reflection and that - // class isn't on the 'shortlist' (in systemClassesContainingReflection). Currently we skip - // this for performance, we could make it optional baed on a configuration option - // } else { - // // We should really track whether this type is using reflection... - // if (SystemClassReflectionInvestigator.investigate(slashedClassName, bytes) > 0) { - // RewriteResult rr = SystemClassReflectionRewriter.rewrite(slashedClassName, bytes); - // System.err.println("Type " + slashedClassName + " rewrite summary: " + rr.summarize()); - // systemClassesRequiringInitialization.put(slashedClassName, rr.bits); - // return rr.bytes; - // } + } else if (slashedClassName.equals("java/lang/invoke/InnerClassLambdaMetafactory")) { bytes = Java8.enhanceInnerClassLambdaMetaFactory(bytes); return bytes; + } else if ((GlobalConfiguration.investigateSystemClassReflection || GlobalConfiguration.rewriteAllSystemClasses) && + SystemClassReflectionInvestigator.investigate(slashedClassName, bytes, GlobalConfiguration.investigateSystemClassReflection) > 0) { + // This block can help when you suspect there is a system class using reflection and that + // class isn't on the 'shortlist' (in systemClassesContainingReflection). Basically turn on the + // options to trigger this investigation then add them to the shortlist if it looks like they need rewriting. + RewriteResult rr = SystemClassReflectionRewriter.rewrite(slashedClassName, bytes); + if (GlobalConfiguration.rewriteAllSystemClasses) { + systemClassesRequiringInitialization.put(slashedClassName, rr.bits); + return rr.bytes; + } + else { + System.err.println("Type " + slashedClassName + " rewrite summary: " + rr.summarize()); + return bytes; + } } } return bytes;