Skip to content

Commit

Permalink
Lookup tools.jar (JDK8) programatically to boost javap performance
Browse files Browse the repository at this point in the history
  • Loading branch information
chriswhocodes committed Feb 27, 2018
1 parent 4bda189 commit 43ba633
Showing 1 changed file with 105 additions and 35 deletions.
Expand Up @@ -7,40 +7,110 @@


import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List; import java.util.List;


import org.adoptopenjdk.jitwatch.loader.DisposableURLClassLoader;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


public class ReflectionJavap public class ReflectionJavap
{ {
private static final Logger logger = LoggerFactory.getLogger(ReflectionJavap.class); private static final Logger logger = LoggerFactory.getLogger(ReflectionJavap.class);


private static final String JAVAP_CLASS = "com.sun.tools.javap.JavapTask"; private static final String JAVAPTASK_CLASS = "com.sun.tools.javap.JavapTask";


private static final int BUFFER_SIZE = 64 * 1024; private static final int BUFFER_SIZE = 64 * 1024;


public static boolean canUseReflectionJavap() private static boolean hasCheckedForToolsJar = false;

private static Boolean canUseReflectionJavap = null;

private static Class<?> classJavapTask;

private static URL locateToolsJar()
{ {
boolean available = false; Path javaHome = Paths.get(System.getProperty("java.home"));

Path toolsJarPath = Paths.get(javaHome.toString(), "..", "lib", "tools.jar").normalize();


try URL result = null;

if (toolsJarPath.toFile().exists())
{ {
Class<?> javapClass = Class.forName(JAVAP_CLASS); try

{
javapClass.getMethod("setLog", new Class[] { OutputStream.class }); result = toolsJarPath.toFile().toURI().toURL();
javapClass.getMethod("handleOptions", new Class[] { String[].class }); }
javapClass.getMethod("call", new Class[] {}); catch (MalformedURLException e)

{
available = true; e.printStackTrace();
}
} }
catch (ClassNotFoundException | NoSuchMethodException | SecurityException e)
return result;
}

public static boolean canUseReflectionJavap()
{
if (canUseReflectionJavap == null)
{ {
boolean available = false;

try
{
classJavapTask = Class.forName(JAVAPTASK_CLASS);
}
catch (ClassNotFoundException cnfe)
{
URL toolsJarURL = locateToolsJar();

if (toolsJarURL != null)
{
List<URL> urls = new ArrayList<>();

urls.add(toolsJarURL);

DisposableURLClassLoader disposableClassLoader = new DisposableURLClassLoader(urls);

try
{
classJavapTask = Class.forName(JAVAPTASK_CLASS, false, disposableClassLoader);
}
catch (ClassNotFoundException cnfe2)
{
cnfe2.printStackTrace();
}
}
}

if (classJavapTask != null)
{
try
{
classJavapTask.getMethod("setLog", new Class[] { OutputStream.class });
classJavapTask.getMethod("handleOptions", new Class[] { String[].class });
classJavapTask.getMethod("call", new Class[] {});

available = true;
}
catch (NoSuchMethodException | SecurityException e)
{
e.printStackTrace();
}
}

canUseReflectionJavap = new Boolean(available);
} }


return available; return canUseReflectionJavap.booleanValue();
} }


public static String getBytecode(List<String> classLocations, String fqClassName) public static String getBytecode(List<String> classLocations, String fqClassName)
Expand All @@ -55,31 +125,31 @@ public static String getBytecode(List<String> classLocations, String fqClassName
private static String createJavapTaskFromArguments(String fqClassName, String[] args) private static String createJavapTaskFromArguments(String fqClassName, String[] args)
{ {
String byteCodeString = null; String byteCodeString = null;

try if (classJavapTask != null)
{ {
Class<?> javapClass = Class.forName(JAVAP_CLASS); try

Object javapObject = javapClass.newInstance();

Method methodSetLog = javapClass.getMethod("setLog", new Class[] { OutputStream.class });
Method methodHandleOptions = javapClass.getMethod("handleOptions", new Class[] { String[].class });
Method methodCall = javapClass.getMethod("call", new Class[] {});

try (ByteArrayOutputStream baos = new ByteArrayOutputStream(BUFFER_SIZE))
{ {
methodSetLog.invoke(javapObject, baos); Object javapObject = classJavapTask.newInstance();
methodHandleOptions.invoke(javapObject, new Object[] {args});
methodCall.invoke(javapObject); Method methodSetLog = classJavapTask.getMethod("setLog", new Class[] { OutputStream.class });

Method methodHandleOptions = classJavapTask.getMethod("handleOptions", new Class[] { String[].class });
byteCodeString = baos.toString(); Method methodCall = classJavapTask.getMethod("call", new Class[] {});

try (ByteArrayOutputStream baos = new ByteArrayOutputStream(BUFFER_SIZE))
{
methodSetLog.invoke(javapObject, baos);
methodHandleOptions.invoke(javapObject, new Object[] {args});
methodCall.invoke(javapObject);

byteCodeString = baos.toString();
}
}
catch (Exception e)
{
logger.error("Could not load bytecode via reflection", e);
} }
} }
catch (Exception e)
{
logger.error("Could not load bytecode via reflection", e);
}

return byteCodeString; return byteCodeString;
} }


Expand Down

0 comments on commit 43ba633

Please sign in to comment.