Load async-profiler.jar if possible when using -Xprofile
Instead of requiring it to be on the compiler classpath. This will make it much easier to profile the Kotlin compiler daemon in Gradle, by just specifying a compiler argument instead of also manually patching the compiler jar.
This commit is contained in:
+35
-17
@@ -5,8 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.common.profiling
|
||||
|
||||
import java.io.File
|
||||
import java.lang.invoke.MethodHandles
|
||||
import java.lang.invoke.MethodType
|
||||
import java.net.URLClassLoader
|
||||
|
||||
interface AsyncProfilerReflected {
|
||||
fun execute(command: String): String
|
||||
@@ -14,24 +16,22 @@ interface AsyncProfilerReflected {
|
||||
val version: String
|
||||
}
|
||||
|
||||
|
||||
|
||||
object AsyncProfilerHelper {
|
||||
private val profilerClass = Class.forName("one.profiler.AsyncProfiler")
|
||||
private val getInstanceHandle =
|
||||
MethodHandles.lookup().findStatic(profilerClass, "getInstance", MethodType.methodType(profilerClass, String::class.java))
|
||||
private val executeHandle =
|
||||
MethodHandles.lookup().findVirtual(
|
||||
profilerClass,
|
||||
"execute",
|
||||
MethodType.methodType(String::class.java, String::class.java)
|
||||
)
|
||||
private val stopHandle =
|
||||
MethodHandles.lookup().findVirtual(profilerClass, "stop", MethodType.methodType(Void.TYPE))
|
||||
private val getVersionHandle =
|
||||
MethodHandles.lookup().findVirtual(profilerClass, "getVersion", MethodType.methodType(String::class.java))
|
||||
|
||||
fun getInstance(libPath: String?): AsyncProfilerReflected {
|
||||
val profilerClass = loadAsyncProfilerClass(libPath)
|
||||
val getInstanceHandle =
|
||||
MethodHandles.lookup().findStatic(profilerClass, "getInstance", MethodType.methodType(profilerClass, String::class.java))
|
||||
val executeHandle =
|
||||
MethodHandles.lookup().findVirtual(
|
||||
profilerClass,
|
||||
"execute",
|
||||
MethodType.methodType(String::class.java, String::class.java)
|
||||
)
|
||||
val stopHandle =
|
||||
MethodHandles.lookup().findVirtual(profilerClass, "stop", MethodType.methodType(Void.TYPE))
|
||||
val getVersionHandle =
|
||||
MethodHandles.lookup().findVirtual(profilerClass, "getVersion", MethodType.methodType(String::class.java))
|
||||
|
||||
val instance = getInstanceHandle.invokeWithArguments(libPath)
|
||||
return object : AsyncProfilerReflected {
|
||||
private val boundExecute = executeHandle.bindTo(instance)
|
||||
@@ -51,4 +51,22 @@ object AsyncProfilerHelper {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadAsyncProfilerClass(libPath: String?): Class<*> {
|
||||
val fqName = "one.profiler.AsyncProfiler"
|
||||
return try {
|
||||
Class.forName(fqName)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
if (libPath == null) throw e
|
||||
else {
|
||||
val directory = File(libPath).parentFile
|
||||
check(directory.isDirectory) { directory }
|
||||
val apiJar = directory.resolve("async-profiler.jar")
|
||||
if (!apiJar.exists())
|
||||
error("To use async-profiler, either add it to the compiler classpath, or put async-profiler.jar at this path: $apiJar")
|
||||
val classLoader = URLClassLoader(arrayOf(apiJar.toURI().toURL()), null)
|
||||
classLoader.loadClass(fqName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user