20
20
[clojure.tools.analyzer.passes.jvm.warn-on-reflection :refer [warn-on-reflection]]
21
21
[clojure.tools.analyzer.jvm :as an-jvm]
22
22
[clojure.core.async.impl.protocols :as impl]
23
+ [clojure.core.async.impl.dispatch :as dispatch]
24
+ [clojure.core.async.impl.runtime :as rt]
23
25
[clojure.set :as set])
24
- (:import [java.util.concurrent.locks Lock ]
25
- [java.util.concurrent.atomic AtomicReferenceArray ]))
26
+ (:import [java.util.concurrent.atomic AtomicReferenceArray ]
27
+ [clojure.lang Var ]))
26
28
27
29
(defn debug [x]
28
30
(pprint x)
29
31
x )
30
32
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
-
56
33
; ; State monad stuff, used only in SSA construction
57
34
58
35
(defmacro gen-plan
217
194
IEmittableInstruction
218
195
(emit-instruction [this state-sym]
219
196
(if (= value ::value )
220
- `[~(:id this) (aget-object ~state-sym ~VALUE-IDX)]
197
+ `[~(:id this) (rt/ aget-object ~state-sym ~rt/ VALUE-IDX)]
221
198
`[~(:id this) ~value])))
222
199
223
200
(defrecord RawCode [ast locals]
317
294
(terminate-block [_this state-sym _]
318
295
`(do (case ~val-id
319
296
~@(concat (mapcat (fn [test blk]
320
- `[~test (aset-all! ~state-sym ~STATE-IDX ~blk)])
297
+ `[~test (rt/ aset-all! ~state-sym ~rt/ STATE-IDX ~blk)])
321
298
test-vals jmp-blocks)
322
299
(when default-block
323
- `[(do (aset-all! ~state-sym ~STATE-IDX ~default-block)
300
+ `[(do (rt/ aset-all! ~state-sym ~rt/ STATE-IDX ~default-block)
324
301
:recur )])))
325
302
:recur )))
326
303
351
328
(block-references [_this] [block])
352
329
ITerminator
353
330
(terminate-block [_this state-sym _]
354
- `(do (aset-all! ~state-sym ~VALUE-IDX ~value ~STATE-IDX ~block)
331
+ `(do (rt/ aset-all! ~state-sym ~rt/ VALUE-IDX ~value ~rt/ STATE-IDX ~block)
355
332
:recur )))
356
333
357
334
(defrecord Return [value]
364
341
(terminate-block [this state-sym custom-terminators]
365
342
(if-let [f (get custom-terminators (terminator-code this))]
366
343
`(~f ~state-sym ~value)
367
- `(do (aset-all! ~state-sym ~VALUE-IDX ~value ~STATE-IDX ::finished )
344
+ `(do (rt/ aset-all! ~state-sym ~rt/ VALUE-IDX ~value ~rt/ STATE-IDX ::finished )
368
345
nil ))))
369
346
370
347
(defrecord CondBr [test then-block else-block]
375
352
ITerminator
376
353
(terminate-block [_this state-sym _]
377
354
`(do (if ~test
378
- (aset-all! ~state-sym ~STATE-IDX ~then-block)
379
- (aset-all! ~state-sym ~STATE-IDX ~else-block))
355
+ (rt/ aset-all! ~state-sym ~rt/ STATE-IDX ~then-block)
356
+ (rt/ aset-all! ~state-sym ~rt/ STATE-IDX ~else-block))
380
357
:recur )))
381
358
382
359
(defrecord PushTry [catch-block]
386
363
(block-references [_this] [catch-block])
387
364
IEmittableInstruction
388
365
(emit-instruction [_this state-sym]
389
- `[~'_ (aset-all! ~state-sym ~EXCEPTION-FRAMES (cons ~catch-block (aget-object ~state-sym ~EXCEPTION-FRAMES)))]))
366
+ `[~'_ (rt/ aset-all! ~state-sym ~rt/ EXCEPTION-FRAMES (cons ~catch-block (rt/ aget-object ~state-sym ~rt/ EXCEPTION-FRAMES)))]))
390
367
391
368
(defrecord PopTry []
392
369
IInstruction
395
372
(block-references [_this] [])
396
373
IEmittableInstruction
397
374
(emit-instruction [_this state-sym]
398
- `[~'_ (aset-all! ~state-sym ~EXCEPTION-FRAMES (rest (aget-object ~state-sym ~EXCEPTION-FRAMES)))]))
375
+ `[~'_ (rt/ aset-all! ~state-sym ~rt/ EXCEPTION-FRAMES (rest (rt/ aget-object ~state-sym ~rt/ EXCEPTION-FRAMES)))]))
399
376
400
377
(defrecord CatchHandler [catches]
401
378
IInstruction
405
382
ITerminator
406
383
(terminate-block [_this state-sym _]
407
384
(let [ex (gensym 'ex)]
408
- `(let [~ex (aget-object ~state-sym ~VALUE-IDX)]
385
+ `(let [~ex (rt/ aget-object ~state-sym ~rt/ VALUE-IDX)]
409
386
(cond
410
387
~@(for [[handler-idx type] catches
411
- i [`(instance? ~type ~ex) `(aset-all! ~state-sym ~STATE-IDX ~handler-idx)]]
388
+ i [`(instance? ~type ~ex) `(rt/ aset-all! ~state-sym ~rt/ STATE-IDX ~handler-idx)]]
412
389
i)
413
390
:else (throw ~ex))
414
391
:recur ))))
888
865
(if (empty? args)
889
866
[]
890
867
(mapcat (fn [sym]
891
- `[~sym (aget-object ~state-sym ~(id-for-inst local-map sym))])
868
+ `[~sym (rt/ aget-object ~state-sym ~(id-for-inst local-map sym))])
892
869
args))))
893
870
894
871
(defn- build-block-body [state-sym blk]
905
882
blk)
906
883
results (interleave (map (partial id-for-inst local-map) results) results)]
907
884
(if-not (empty? results)
908
- [state-sym `(aset-all! ~state-sym ~@results)]
885
+ [state-sym `(rt/ aset-all! ~state-sym ~@results)]
909
886
[])))
910
887
911
888
(defn- emit-state-machine [machine num-user-params custom-terminators]
912
889
(let [index (index-state-machine machine)
913
890
state-sym (with-meta (gensym " state_" )
914
891
{:tag 'objects})
915
- local-start-idx (+ num-user-params USER-START-IDX)
892
+ local-start-idx (+ num-user-params rt/ USER-START-IDX)
916
893
state-arr-size (+ local-start-idx (count-persistent-values index))
917
894
local-map (atom {::next-idx local-start-idx})
918
895
block-catches (:block-catches machine)]
919
896
`(fn state-machine#
920
- ([] (aset-all! (AtomicReferenceArray. ~state-arr-size)
921
- ~FN-IDX state-machine#
922
- ~STATE-IDX ~(:start-block machine)))
897
+ ([] (rt/ aset-all! (AtomicReferenceArray. ~state-arr-size)
898
+ ~rt/ FN-IDX state-machine#
899
+ ~rt/ STATE-IDX ~(:start-block machine)))
923
900
([~state-sym]
924
901
(let [old-frame# (clojure.lang.Var/getThreadBindingFrame )
925
902
ret-value# (try
926
- (clojure.lang.Var/resetThreadBindingFrame (aget-object ~state-sym ~BINDINGS-IDX))
903
+ (clojure.lang.Var/resetThreadBindingFrame (rt/ aget-object ~state-sym ~rt/ BINDINGS-IDX))
927
904
(loop []
928
- (let [result# (case (int (aget-object ~state-sym ~STATE-IDX))
905
+ (let [result# (case (int (rt/ aget-object ~state-sym ~rt/ STATE-IDX))
929
906
~@(mapcat
930
907
(fn [[id blk]]
931
908
[id `(let [~@(concat (build-block-preamble local-map index state-sym blk)
937
914
(recur )
938
915
result#)))
939
916
(catch Throwable ex#
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
+ (rt/ aset-all! ~state-sym ~rt/ VALUE-IDX ex#)
918
+ (if (seq (rt/ aget-object ~state-sym ~rt/ EXCEPTION-FRAMES))
919
+ (rt/ aset-all! ~state-sym ~rt/ STATE-IDX (first (rt/ aget-object ~state-sym ~rt/ EXCEPTION-FRAMES)))
943
920
(throw ex#))
944
921
:recur )
945
922
(finally
946
- (aset-object ~state-sym ~BINDINGS-IDX (clojure.lang.Var/getThreadBindingFrame ))
923
+ (rt/ aset-object ~state-sym ~rt/ BINDINGS-IDX (clojure.lang.Var/getThreadBindingFrame ))
947
924
(clojure.lang.Var/resetThreadBindingFrame old-frame#)))]
948
925
(if (identical? ret-value# :recur )
949
926
(recur ~state-sym)
950
927
ret-value#))))))
951
928
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
-
1011
929
(defn mark-transitions
1012
930
{:pass-info {:walk :post :depends #{} :after an-jvm/default-passes}}
1013
931
[{:keys [op fn ] :as ast}]
1110
1028
(parse-to-state-machine user-transitions)
1111
1029
second
1112
1030
(emit-state-machine num-user-params user-transitions))))
1031
+
1032
+ (defn go-impl
1033
+ [env body]
1034
+ (let [crossing-env (zipmap (keys env) (repeatedly gensym))]
1035
+ `(let [c# (clojure.core.async/chan 1 )
1036
+ captured-bindings# (Var/getThreadBindingFrame )]
1037
+ (dispatch/run
1038
+ (^:once fn* []
1039
+ (let [~@(mapcat (fn [[l sym]] [sym `(^:once fn* [] ~(vary-meta l dissoc :tag ))]) crossing-env)
1040
+ f# ~(state-machine
1041
+ `(do ~@body) 1 [crossing-env env] rt/async-custom-terminators)
1042
+ state# (-> (f# )
1043
+ (rt/aset-all! rt/USER-START-IDX c#
1044
+ rt/BINDINGS-IDX captured-bindings#))]
1045
+ (rt/run-state-machine-wrapped state#))))
1046
+ c#)))
0 commit comments