|
19 | 19 | [clojure.tools.analyzer.passes.jvm.annotate-loops :refer [annotate-loops]]
|
20 | 20 | [clojure.tools.analyzer.passes.jvm.warn-on-reflection :refer [warn-on-reflection]]
|
21 | 21 | [clojure.tools.analyzer.jvm :as an-jvm]
|
22 |
| - [clojure.core.async.impl.runtime :as rt] |
| 22 | + [clojure.core.async.impl.protocols :as impl] |
23 | 23 | [clojure.set :as set])
|
24 |
| - (:import [java.util.concurrent.atomic AtomicReferenceArray])) |
| 24 | + (:import [java.util.concurrent.locks Lock] |
| 25 | + [java.util.concurrent.atomic AtomicReferenceArray])) |
25 | 26 |
|
26 | 27 | (defn debug [x]
|
27 | 28 | (pprint x)
|
28 | 29 | x)
|
29 | 30 |
|
| 31 | +(def ^{:const true :tag 'long} FN-IDX 0) |
| 32 | +(def ^{:const true :tag 'long} STATE-IDX 1) |
| 33 | +(def ^{:const true :tag 'long} VALUE-IDX 2) |
| 34 | +(def ^{:const true :tag 'long} BINDINGS-IDX 3) |
| 35 | +(def ^{:const true :tag 'long} EXCEPTION-FRAMES 4) |
| 36 | +(def ^{:const true :tag 'long} USER-START-IDX 5) |
| 37 | + |
| 38 | +(defn aset-object [^AtomicReferenceArray arr ^long idx o] |
| 39 | + (.set arr idx o)) |
| 40 | + |
| 41 | +(defn aget-object [^AtomicReferenceArray arr ^long idx] |
| 42 | + (.get arr idx)) |
| 43 | + |
| 44 | +(defmacro aset-all! |
| 45 | + [arr & more] |
| 46 | + (assert (even? (count more)) "Must give an even number of args to aset-all!") |
| 47 | + (let [bindings (partition 2 more) |
| 48 | + arr-sym (gensym "statearr-")] |
| 49 | + `(let [~arr-sym ~arr] |
| 50 | + ~@(map |
| 51 | + (fn [[idx val]] |
| 52 | + `(aset-object ~arr-sym ~idx ~val)) |
| 53 | + bindings) |
| 54 | + ~arr-sym))) |
| 55 | + |
30 | 56 | ;; State monad stuff, used only in SSA construction
|
31 | 57 |
|
32 | 58 | (defmacro gen-plan
|
|
191 | 217 | IEmittableInstruction
|
192 | 218 | (emit-instruction [this state-sym]
|
193 | 219 | (if (= value ::value)
|
194 |
| - `[~(:id this) (rt/aget-object ~state-sym ~rt/VALUE-IDX)] |
| 220 | + `[~(:id this) (aget-object ~state-sym ~VALUE-IDX)] |
195 | 221 | `[~(:id this) ~value])))
|
196 | 222 |
|
197 | 223 | (defrecord RawCode [ast locals]
|
|
291 | 317 | (terminate-block [_this state-sym _]
|
292 | 318 | `(do (case ~val-id
|
293 | 319 | ~@(concat (mapcat (fn [test blk]
|
294 |
| - `[~test (rt/aset-all! ~state-sym ~rt/STATE-IDX ~blk)]) |
| 320 | + `[~test (aset-all! ~state-sym ~STATE-IDX ~blk)]) |
295 | 321 | test-vals jmp-blocks)
|
296 | 322 | (when default-block
|
297 |
| - `[(do (rt/aset-all! ~state-sym ~rt/STATE-IDX ~default-block) |
| 323 | + `[(do (aset-all! ~state-sym ~STATE-IDX ~default-block) |
298 | 324 | :recur)])))
|
299 | 325 | :recur)))
|
300 | 326 |
|
|
325 | 351 | (block-references [_this] [block])
|
326 | 352 | ITerminator
|
327 | 353 | (terminate-block [_this state-sym _]
|
328 |
| - `(do (rt/aset-all! ~state-sym ~rt/VALUE-IDX ~value ~rt/STATE-IDX ~block) |
| 354 | + `(do (aset-all! ~state-sym ~VALUE-IDX ~value ~STATE-IDX ~block) |
329 | 355 | :recur)))
|
330 | 356 |
|
331 | 357 | (defrecord Return [value]
|
|
338 | 364 | (terminate-block [this state-sym custom-terminators]
|
339 | 365 | (if-let [f (get custom-terminators (terminator-code this))]
|
340 | 366 | `(~f ~state-sym ~value)
|
341 |
| - `(do (rt/aset-all! ~state-sym ~rt/VALUE-IDX ~value ~rt/STATE-IDX ::finished) |
| 367 | + `(do (aset-all! ~state-sym ~VALUE-IDX ~value ~STATE-IDX ::finished) |
342 | 368 | nil))))
|
343 | 369 |
|
344 | 370 | (defrecord CondBr [test then-block else-block]
|
|
349 | 375 | ITerminator
|
350 | 376 | (terminate-block [_this state-sym _]
|
351 | 377 | `(do (if ~test
|
352 |
| - (rt/aset-all! ~state-sym ~rt/STATE-IDX ~then-block) |
353 |
| - (rt/aset-all! ~state-sym ~rt/STATE-IDX ~else-block)) |
| 378 | + (aset-all! ~state-sym ~STATE-IDX ~then-block) |
| 379 | + (aset-all! ~state-sym ~STATE-IDX ~else-block)) |
354 | 380 | :recur)))
|
355 | 381 |
|
356 | 382 | (defrecord PushTry [catch-block]
|
|
360 | 386 | (block-references [_this] [catch-block])
|
361 | 387 | IEmittableInstruction
|
362 | 388 | (emit-instruction [_this state-sym]
|
363 |
| - `[~'_ (rt/aset-all! ~state-sym ~rt/EXCEPTION-FRAMES (cons ~catch-block (rt/aget-object ~state-sym ~rt/EXCEPTION-FRAMES)))])) |
| 389 | + `[~'_ (aset-all! ~state-sym ~EXCEPTION-FRAMES (cons ~catch-block (aget-object ~state-sym ~EXCEPTION-FRAMES)))])) |
364 | 390 |
|
365 | 391 | (defrecord PopTry []
|
366 | 392 | IInstruction
|
|
369 | 395 | (block-references [_this] [])
|
370 | 396 | IEmittableInstruction
|
371 | 397 | (emit-instruction [_this state-sym]
|
372 |
| - `[~'_ (rt/aset-all! ~state-sym ~rt/EXCEPTION-FRAMES (rest (rt/aget-object ~state-sym ~rt/EXCEPTION-FRAMES)))])) |
| 398 | + `[~'_ (aset-all! ~state-sym ~EXCEPTION-FRAMES (rest (aget-object ~state-sym ~EXCEPTION-FRAMES)))])) |
373 | 399 |
|
374 | 400 | (defrecord CatchHandler [catches]
|
375 | 401 | IInstruction
|
|
379 | 405 | ITerminator
|
380 | 406 | (terminate-block [_this state-sym _]
|
381 | 407 | (let [ex (gensym 'ex)]
|
382 |
| - `(let [~ex (rt/aget-object ~state-sym ~rt/VALUE-IDX)] |
| 408 | + `(let [~ex (aget-object ~state-sym ~VALUE-IDX)] |
383 | 409 | (cond
|
384 | 410 | ~@(for [[handler-idx type] catches
|
385 |
| - i [`(instance? ~type ~ex) `(rt/aset-all! ~state-sym ~rt/STATE-IDX ~handler-idx)]] |
| 411 | + i [`(instance? ~type ~ex) `(aset-all! ~state-sym ~STATE-IDX ~handler-idx)]] |
386 | 412 | i)
|
387 | 413 | :else (throw ~ex))
|
388 | 414 | :recur))))
|
|
862 | 888 | (if (empty? args)
|
863 | 889 | []
|
864 | 890 | (mapcat (fn [sym]
|
865 |
| - `[~sym (rt/aget-object ~state-sym ~(id-for-inst local-map sym))]) |
| 891 | + `[~sym (aget-object ~state-sym ~(id-for-inst local-map sym))]) |
866 | 892 | args))))
|
867 | 893 |
|
868 | 894 | (defn- build-block-body [state-sym blk]
|
|
879 | 905 | blk)
|
880 | 906 | results (interleave (map (partial id-for-inst local-map) results) results)]
|
881 | 907 | (if-not (empty? results)
|
882 |
| - [state-sym `(rt/aset-all! ~state-sym ~@results)] |
| 908 | + [state-sym `(aset-all! ~state-sym ~@results)] |
883 | 909 | [])))
|
884 | 910 |
|
885 | 911 | (defn- emit-state-machine [machine num-user-params custom-terminators]
|
886 | 912 | (let [index (index-state-machine machine)
|
887 | 913 | state-sym (with-meta (gensym "state_")
|
888 | 914 | {:tag 'objects})
|
889 |
| - local-start-idx (+ num-user-params rt/USER-START-IDX) |
| 915 | + local-start-idx (+ num-user-params USER-START-IDX) |
890 | 916 | state-arr-size (+ local-start-idx (count-persistent-values index))
|
891 | 917 | local-map (atom {::next-idx local-start-idx})
|
892 | 918 | block-catches (:block-catches machine)]
|
893 | 919 | `(fn state-machine#
|
894 |
| - ([] (rt/aset-all! (AtomicReferenceArray. ~state-arr-size) |
895 |
| - ~rt/FN-IDX state-machine# |
896 |
| - ~rt/STATE-IDX ~(:start-block machine))) |
| 920 | + ([] (aset-all! (AtomicReferenceArray. ~state-arr-size) |
| 921 | + ~FN-IDX state-machine# |
| 922 | + ~STATE-IDX ~(:start-block machine))) |
897 | 923 | ([~state-sym]
|
898 | 924 | (let [old-frame# (clojure.lang.Var/getThreadBindingFrame)
|
899 | 925 | ret-value# (try
|
900 |
| - (clojure.lang.Var/resetThreadBindingFrame (rt/aget-object ~state-sym ~rt/BINDINGS-IDX)) |
| 926 | + (clojure.lang.Var/resetThreadBindingFrame (aget-object ~state-sym ~BINDINGS-IDX)) |
901 | 927 | (loop []
|
902 |
| - (let [result# (case (int (rt/aget-object ~state-sym ~rt/STATE-IDX)) |
| 928 | + (let [result# (case (int (aget-object ~state-sym ~STATE-IDX)) |
903 | 929 | ~@(mapcat
|
904 | 930 | (fn [[id blk]]
|
905 | 931 | [id `(let [~@(concat (build-block-preamble local-map index state-sym blk)
|
|
911 | 937 | (recur)
|
912 | 938 | result#)))
|
913 | 939 | (catch Throwable ex#
|
914 |
| - (rt/aset-all! ~state-sym ~rt/VALUE-IDX ex#) |
915 |
| - (if (seq (rt/aget-object ~state-sym ~rt/EXCEPTION-FRAMES)) |
916 |
| - (rt/aset-all! ~state-sym ~rt/STATE-IDX (first (rt/aget-object ~state-sym ~rt/EXCEPTION-FRAMES))) |
| 940 | + (aset-all! ~state-sym ~VALUE-IDX ex#) |
| 941 | + (if (seq (aget-object ~state-sym ~EXCEPTION-FRAMES)) |
| 942 | + (aset-all! ~state-sym ~STATE-IDX (first (aget-object ~state-sym ~EXCEPTION-FRAMES))) |
917 | 943 | (throw ex#))
|
918 | 944 | :recur)
|
919 | 945 | (finally
|
920 |
| - (rt/aset-object ~state-sym ~rt/BINDINGS-IDX (clojure.lang.Var/getThreadBindingFrame)) |
| 946 | + (aset-object ~state-sym ~BINDINGS-IDX (clojure.lang.Var/getThreadBindingFrame)) |
921 | 947 | (clojure.lang.Var/resetThreadBindingFrame old-frame#)))]
|
922 | 948 | (if (identical? ret-value# :recur)
|
923 | 949 | (recur ~state-sym)
|
924 | 950 | ret-value#))))))
|
925 | 951 |
|
| 952 | +(defn finished? |
| 953 | + "Returns true if the machine is in a finished state" |
| 954 | + [state-array] |
| 955 | + (identical? (aget-object state-array STATE-IDX) ::finished)) |
| 956 | + |
| 957 | +(defn- fn-handler |
| 958 | + [f] |
| 959 | + (reify |
| 960 | + Lock |
| 961 | + (lock [_]) |
| 962 | + (unlock [_]) |
| 963 | + |
| 964 | + impl/Handler |
| 965 | + (active? [_] true) |
| 966 | + (blockable? [_] true) |
| 967 | + (lock-id [_] 0) |
| 968 | + (commit [_] f))) |
| 969 | + |
| 970 | + |
| 971 | +(defn run-state-machine [state] |
| 972 | + ((aget-object state FN-IDX) state)) |
| 973 | + |
| 974 | +(defn run-state-machine-wrapped [state] |
| 975 | + (try |
| 976 | + (run-state-machine state) |
| 977 | + (catch Throwable ex |
| 978 | + (impl/close! (aget-object state USER-START-IDX)) |
| 979 | + (throw ex)))) |
| 980 | + |
| 981 | +(defn take! [state blk c] |
| 982 | + (if-let [cb (impl/take! c (fn-handler |
| 983 | + (fn [x] |
| 984 | + (aset-all! state VALUE-IDX x STATE-IDX blk) |
| 985 | + (run-state-machine-wrapped state))))] |
| 986 | + (do (aset-all! state VALUE-IDX @cb STATE-IDX blk) |
| 987 | + :recur) |
| 988 | + nil)) |
| 989 | + |
| 990 | +(defn put! [state blk c val] |
| 991 | + (if-let [cb (impl/put! c val (fn-handler (fn [ret-val] |
| 992 | + (aset-all! state VALUE-IDX ret-val STATE-IDX blk) |
| 993 | + (run-state-machine-wrapped state))))] |
| 994 | + (do (aset-all! state VALUE-IDX @cb STATE-IDX blk) |
| 995 | + :recur) |
| 996 | + nil)) |
| 997 | + |
| 998 | +(defn return-chan [state value] |
| 999 | + (let [c (aget-object state USER-START-IDX)] |
| 1000 | + (when-not (nil? value) |
| 1001 | + (impl/put! c value (fn-handler (fn [_] nil)))) |
| 1002 | + (impl/close! c) |
| 1003 | + c)) |
| 1004 | + |
| 1005 | +(def async-custom-terminators |
| 1006 | + {'clojure.core.async/<! `take! |
| 1007 | + 'clojure.core.async/>! `put! |
| 1008 | + 'clojure.core.async/alts! 'clojure.core.async/ioc-alts! |
| 1009 | + :Return `return-chan}) |
| 1010 | + |
926 | 1011 | (defn mark-transitions
|
927 | 1012 | {:pass-info {:walk :post :depends #{} :after an-jvm/default-passes}}
|
928 | 1013 | [{:keys [op fn] :as ast}]
|
|
0 commit comments