This library offers a fix for an issue with clojure.lang.Reflector
when used
together with GraalVM native-image
on java11.
Include this library in your leiningen profile or deps.edn alias so it's
available on the classpath for GraalVM native-image
. E.g.:
(defproject foo "0.0.1-SNAPSHOT"
:profiles {:native-image {:dependencies [[borkdude/clj-reflector-graal-java11-fix "0.0.1-graalvm-19.3.2"]]}})
Use the right GraalVM version modifier: graalvm-19.3.1
or
graalvm-20.0.0
. The modifier must exactly match the version of GraalVM
native-image
.
Do NOT distribute this library as part of libraries or applications that are run with a JVM. Use it for compiling to native binaries only.
E.g. to produce an uberjar that is fed to native-image
you can do:
$ lein with-profiles +native-image do clean, uberjar
and then:
$ native-image -jar target/foo-0.0.1-SNAPSHOT-standalone.jar
JDK11 is supported since GraalVM 19.3.0. The class clojure.lang.Reflector
uses
a MethodHandle
to maintain compatibility with java8 and java11 at the same
time:
static {
MethodHandle pred = null;
try {
if (! isJava8())
pred = MethodHandles.lookup().findVirtual(Method.class, "canAccess", MethodType.methodType(boolean.class, Object.class));
} catch (Throwable t) {
Util.sneakyThrow(t);
}
CAN_ACCESS_PRED = pred;
}
GraalVM does not support MethodHandle
s that cannot be analyzed as a compile
time constant. It will complain when it analyzes clojure.lang.Reflector
on
JDK11:
Exception in thread "main" com.oracle.svm.core.jdk.UnsupportedFeatureError: Invoke with MethodHandle argument could not be reduced to at most a single call or single field access. The method handle must be a compile time constant, e.g., be loaded from a `static final` field. Method that contains the method handle invocation: java.lang.invoke.Invokers$Holder.invoke_MT(Object, Object, Object, Object)
at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:101)
at clojure.lang.Reflector.canAccess(Reflector.java:49)
...
See the issue on the GraalVM repo.
GraalVM supports substitutions. For JDK11 or later the method canAccess
is replaced as follows:
@TargetClass(className = "clojure.lang.Reflector")
final class Target_clojure_lang_Reflector {
@Substitute
@TargetElement(onlyWith = JDK11OrLater.class)
private static boolean canAccess(Method m, Object target) {
// JDK9+ use j.l.r.AccessibleObject::canAccess, which respects module rules
try {
return (boolean) m.canAccess(target);
} catch (Throwable t) {
throw Util.sneakyThrow(t);
}
}
}
Copyright © 2020 Michiel Borkent
Distributed under the EPL License. See LICENSE.
This project contains code from:
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close