cljs inline caching impl almost working
This commit is contained in:
parent
2071059695
commit
d30af6e972
2 changed files with 84 additions and 42 deletions
|
|
@ -619,7 +619,7 @@
|
||||||
[val sym])
|
[val sym])
|
||||||
|
|
||||||
(defrecord VarUse
|
(defrecord VarUse
|
||||||
[var sym])
|
[val var sym])
|
||||||
|
|
||||||
(defrecord SpecialFormUse
|
(defrecord SpecialFormUse
|
||||||
[val code])
|
[val code])
|
||||||
|
|
@ -635,6 +635,8 @@
|
||||||
|
|
||||||
(defonce PATH-CACHE
|
(defonce PATH-CACHE
|
||||||
#+clj (java.util.concurrent.ConcurrentHashMap.)
|
#+clj (java.util.concurrent.ConcurrentHashMap.)
|
||||||
|
;;TODO: according to @dnolen, can forgo this for instead doing
|
||||||
|
;;inline defs at runtime
|
||||||
#+cljs (atom {})
|
#+cljs (atom {})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -674,9 +676,20 @@
|
||||||
(satisfies? p/Collector v)
|
(satisfies? p/Collector v)
|
||||||
(instance? CompiledPath v)))
|
(instance? CompiledPath v)))
|
||||||
|
|
||||||
(defn magic-fail! [failed-atom]
|
#+clj
|
||||||
(reset! failed-atom true)
|
(def ^:dynamic *used-locals*)
|
||||||
nil)
|
|
||||||
|
#+clj
|
||||||
|
(defmacro handle-params [precompiled params-maker possible-params]
|
||||||
|
`(bind-params* ~precompiled (~params-maker ~@*used-locals*) 0))
|
||||||
|
|
||||||
|
#+cljs
|
||||||
|
(defn handle-params [precompiled params-maker possible-params]
|
||||||
|
(let [params (fast-object-array (count params-maker))]
|
||||||
|
(doseq [i params-maker]
|
||||||
|
(aset params i ((get possible-params i))))
|
||||||
|
(bind-params* precompiled params 0)
|
||||||
|
))
|
||||||
|
|
||||||
(def pred*
|
(def pred*
|
||||||
(->ParamsNeededPath
|
(->ParamsNeededPath
|
||||||
|
|
@ -713,7 +726,7 @@
|
||||||
|
|
||||||
(instance? VarUse p)
|
(instance? VarUse p)
|
||||||
(let [v (:var p)
|
(let [v (:var p)
|
||||||
vv (var-get v)]
|
vv (:val p)]
|
||||||
(cond (-> v meta :dynamic) (magic-fail! "Var " (:sym p) " is dynamic")
|
(cond (-> v meta :dynamic) (magic-fail! "Var " (:sym p) " is dynamic")
|
||||||
(valid-navigator? vv) vv
|
(valid-navigator? vv) vv
|
||||||
:else (magic-fail! "Var " (:sym p) " is not a navigator")
|
:else (magic-fail! "Var " (:sym p) " is not a navigator")
|
||||||
|
|
@ -733,7 +746,7 @@
|
||||||
ps (:params p)]
|
ps (:params p)]
|
||||||
(if (instance? VarUse op)
|
(if (instance? VarUse op)
|
||||||
(let [v (:var op)
|
(let [v (:var op)
|
||||||
vv (var-get v)]
|
vv (:val op)]
|
||||||
(if (-> v meta :dynamic)
|
(if (-> v meta :dynamic)
|
||||||
(magic-fail! "Var " (:sym op) " is dynamic")
|
(magic-fail! "Var " (:sym op) " is dynamic")
|
||||||
(cond
|
(cond
|
||||||
|
|
@ -782,7 +795,30 @@
|
||||||
)
|
)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(defn magic-precompilation [prepared-path used-locals]
|
#+clj
|
||||||
|
(defn mk-params-maker [params-code possible-params-code used-locals]
|
||||||
|
(let [array-sym (gensym "array")]
|
||||||
|
(eval
|
||||||
|
`(fn [~@used-locals]
|
||||||
|
(let [~array-sym (fast-object-array ~(count params-code))]
|
||||||
|
~@(map-indexed
|
||||||
|
(fn [i c]
|
||||||
|
`(aset ~array-sym ~i ~c))
|
||||||
|
params-code
|
||||||
|
)
|
||||||
|
~array-sym
|
||||||
|
)))))
|
||||||
|
|
||||||
|
#+cljs
|
||||||
|
(defn mk-params-maker [params-code possible-params-code used-locals]
|
||||||
|
(let [indexed (->> possible-params-code
|
||||||
|
(map-indexed (comp vec reverse vector))
|
||||||
|
(into {}))]
|
||||||
|
;;TODO: may be more efficient as an array
|
||||||
|
(mapv (fn [c] (get indexed c)) params-code)))
|
||||||
|
|
||||||
|
;; possible-params-code is for cljs impl that can't use eval
|
||||||
|
(defn magic-precompilation [prepared-path used-locals possible-params-code]
|
||||||
(let [params-atom (atom [])
|
(let [params-atom (atom [])
|
||||||
failed-atom (atom false)
|
failed-atom (atom false)
|
||||||
path (magic-precompilation* prepared-path params-atom failed-atom)
|
path (magic-precompilation* prepared-path params-atom failed-atom)
|
||||||
|
|
@ -793,19 +829,8 @@
|
||||||
(->CachedPathInfo nil nil))
|
(->CachedPathInfo nil nil))
|
||||||
(let [precompiled (comp-paths* path)
|
(let [precompiled (comp-paths* path)
|
||||||
params-code (mapv extract-original-code @params-atom)
|
params-code (mapv extract-original-code @params-atom)
|
||||||
array-sym (gensym "array")
|
params-maker (if-not (empty? params-code)
|
||||||
params-maker
|
(mk-params-maker params-code possible-params-code used-locals))
|
||||||
(if-not (empty? params-code)
|
|
||||||
(eval
|
|
||||||
`(fn [~@used-locals]
|
|
||||||
(let [~array-sym (fast-object-array ~(count params-code))]
|
|
||||||
~@(map-indexed
|
|
||||||
(fn [i c]
|
|
||||||
`(aset ~array-sym ~i ~c))
|
|
||||||
params-code
|
|
||||||
)
|
|
||||||
~array-sym
|
|
||||||
))))
|
|
||||||
]
|
]
|
||||||
;; TODO: error if precompiled is compiledpath and there are params or
|
;; TODO: error if precompiled is compiledpath and there are params or
|
||||||
;; precompiled is paramsneededpath and there are no params...
|
;; precompiled is paramsneededpath and there are no params...
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,8 @@
|
||||||
(symbol? path)
|
(symbol? path)
|
||||||
(if (contains? locals-set path)
|
(if (contains? locals-set path)
|
||||||
`(com.rpl.specter.impl/->LocalSym ~path (quote ~path))
|
`(com.rpl.specter.impl/->LocalSym ~path (quote ~path))
|
||||||
`(com.rpl.specter.impl/->VarUse (var ~path) (quote ~path))
|
;; var-get doesn't work in cljs, so capture the val in the macro instead
|
||||||
|
`(com.rpl.specter.impl/->VarUse ~path (var ~path) (quote ~path))
|
||||||
)
|
)
|
||||||
|
|
||||||
(i/fn-invocation? path)
|
(i/fn-invocation? path)
|
||||||
|
|
@ -344,11 +345,20 @@
|
||||||
`(quote ~path)
|
`(quote ~path)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
(defn ic-possible-params [path]
|
||||||
|
(do
|
||||||
|
(mapcat
|
||||||
|
(fn [e]
|
||||||
|
(if (i/fn-invocation? e)
|
||||||
|
(concat (-> e rest) (ic-possible-params e))))
|
||||||
|
path)))
|
||||||
|
|
||||||
;; still possible to mess this up with alter-var-root
|
;; still possible to mess this up with alter-var-root
|
||||||
(defmacro path [& path] ; "inline cache"
|
(defmacro path [& path] ; "inline cache"
|
||||||
(let [local-syms (-> &env keys set)
|
(let [local-syms (-> &env keys set)
|
||||||
used-locals (vec (i/walk-select local-syms vector path))
|
used-locals (vec (i/walk-select local-syms vector path))
|
||||||
prepared-path (ic-prepare-path local-syms (walk/macroexpand-all (vec path)))
|
prepared-path (ic-prepare-path local-syms (walk/macroexpand-all (vec path)))
|
||||||
|
possible-params (vec (ic-possible-params path))
|
||||||
;; TODO: unclear if using long here versus string makes
|
;; TODO: unclear if using long here versus string makes
|
||||||
;; a significant difference
|
;; a significant difference
|
||||||
;; - but using random longs creates possibility of collisions
|
;; - but using random longs creates possibility of collisions
|
||||||
|
|
@ -360,6 +370,9 @@
|
||||||
;; a bunch of checks beforehand
|
;; a bunch of checks beforehand
|
||||||
cache-id (str (java.util.UUID/randomUUID))
|
cache-id (str (java.util.UUID/randomUUID))
|
||||||
]
|
]
|
||||||
|
(binding [i/*used-locals* used-locals]
|
||||||
|
;; in order to pass the used locals to the clj handle-params macro
|
||||||
|
(walk/macroexpand-all
|
||||||
`(let [info# (i/get-path-cache ~cache-id)
|
`(let [info# (i/get-path-cache ~cache-id)
|
||||||
|
|
||||||
^com.rpl.specter.impl.CachedPathInfo info#
|
^com.rpl.specter.impl.CachedPathInfo info#
|
||||||
|
|
@ -367,7 +380,8 @@
|
||||||
info#
|
info#
|
||||||
(let [info# (i/magic-precompilation
|
(let [info# (i/magic-precompilation
|
||||||
~prepared-path
|
~prepared-path
|
||||||
~(mapv (fn [e] `(quote ~e)) used-locals)
|
(quote ~used-locals)
|
||||||
|
(quote ~possible-params)
|
||||||
)]
|
)]
|
||||||
(i/add-path-cache! ~cache-id info#)
|
(i/add-path-cache! ~cache-id info#)
|
||||||
info#
|
info#
|
||||||
|
|
@ -378,10 +392,13 @@
|
||||||
(if (some? precompiled#)
|
(if (some? precompiled#)
|
||||||
(if (nil? params-maker#)
|
(if (nil? params-maker#)
|
||||||
precompiled#
|
precompiled#
|
||||||
(i/bind-params* precompiled# (params-maker# ~@used-locals) 0)
|
(i/handle-params
|
||||||
)
|
precompiled#
|
||||||
(i/comp-paths* ~(vec path))
|
params-maker#
|
||||||
|
~(mapv (fn [p] `(fn [] ~p)) possible-params)
|
||||||
))
|
))
|
||||||
|
(i/comp-paths* ~(vec path))
|
||||||
|
))))
|
||||||
))
|
))
|
||||||
|
|
||||||
(defmacro select [apath structure]
|
(defmacro select [apath structure]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue