cljs inline caching impl almost working

This commit is contained in:
Nathan Marz 2016-05-23 08:18:49 -04:00
parent 2071059695
commit d30af6e972
2 changed files with 84 additions and 42 deletions

View file

@ -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...

View file

@ -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,28 +370,35 @@
;; a bunch of checks beforehand ;; a bunch of checks beforehand
cache-id (str (java.util.UUID/randomUUID)) cache-id (str (java.util.UUID/randomUUID))
] ]
`(let [info# (i/get-path-cache ~cache-id) (binding [i/*used-locals* used-locals]
;; in order to pass the used locals to the clj handle-params macro
^com.rpl.specter.impl.CachedPathInfo info# (walk/macroexpand-all
(if (some? info#) `(let [info# (i/get-path-cache ~cache-id)
info#
(let [info# (i/magic-precompilation ^com.rpl.specter.impl.CachedPathInfo info#
~prepared-path (if (some? info#)
~(mapv (fn [e] `(quote ~e)) used-locals) info#
)] (let [info# (i/magic-precompilation
(i/add-path-cache! ~cache-id info#) ~prepared-path
info# (quote ~used-locals)
)) (quote ~possible-params)
)]
(i/add-path-cache! ~cache-id info#)
info#
))
precompiled# (.-precompiled info#) precompiled# (.-precompiled info#)
params-maker# (.-params-maker info#)] params-maker# (.-params-maker info#)]
(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]