Skip to content

Commit

Permalink
Workaround locking issue in 1.10
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorwood committed Apr 9, 2019
1 parent dc49100 commit 12b96b5
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.cpcache
classes
clojurl
/clojurl
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,16 @@ should satisfy
-------------------------
Detected 1 error
```

## Compiling with Clojure 1.10

GraalVM native-image won't work with Clojure's `locking` macro, and Clojure 1.10 depends on a version of clojure.spec
(see [this commit](https://github.com/clojure/spec.alpha/commit/31165fec69ff86129a1ada8b3f50864922dfc88a)) that uses `locking`.
You can workaround this by compiling a Java class with a special locking mechanism, and patching any usages of `locking` e.g. in clojure.spec.

You must first compile the Java class:
```
➜ javac java/src/clojurl/LockFix.java -cp ~/.m2/repository/org/clojure/clojure/1.10.0/clojure-1.10.0.jar
```

Then patch any usages of `locking` and you should be able to compile a native image. See `clojurl.clj` for example.
3 changes: 2 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{:deps {expound {:mvn/version "0.7.1"}
org.clojure/clojure {:mvn/version "1.9.0"}
org.clojure/clojure {:mvn/version "1.10.0"}
org.clojure/tools.cli {:mvn/version "0.4.1"}
org.martinklepsch/clj-http-lite {:mvn/version "0.4.1"}
hickory {:mvn/version "0.7.1"}}
:paths ["src" "java/src"]
:aliases {:native-image
{:main-opts ["-m clj.native-image clojurl"
"--report-unsupported-elements-at-runtime"
Expand Down
11 changes: 11 additions & 0 deletions java/src/clojurl/LockFix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package clojurl;

import clojure.lang.IFn;

public class LockFix {
static public Object lock(final Object lockee, final IFn f) {
synchronized (lockee) {
return f.invoke();
}
}
}
24 changes: 23 additions & 1 deletion src/clojurl.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,32 @@
[clojure.pprint :refer [pprint]]
[expound.alpha :as expound]
[hickory.core :as hick])
(:gen-class))
(:gen-class)
(:import (clojurl LockFix)))

(set! *warn-on-reflection* true)

(defmacro locking* ;; patched version of clojure.core/locking to workaround GraalVM unbalanced monitor issue
"Executes exprs in an implicit do, while holding the monitor of x.
Will release the monitor of x in all circumstances."
{:added "1.0"}
[x & body]
`(let [lockee# ~x]
(LockFix/lock lockee# (^{:once true} fn* [] ~@body))))

(defn dynaload ;; patched version of clojure.spec.gen.alpha/dynaload to use patched locking macro
[s]
(let [ns (namespace s)]
(assert ns)
(locking* #'clojure.spec.gen.alpha/dynalock
(require (symbol ns)))
(let [v (resolve s)]
(if v
@v
(throw (RuntimeException. (str "Var " s " is not on the classpath")))))))

(alter-var-root #'clojure.spec.gen.alpha/dynaload (constantly dynaload))

(def cli-options
[["-u" "--uri URI" "URI of request"
:id :url
Expand Down

0 comments on commit 12b96b5

Please sign in to comment.