Skip to content

Commit 4e64079

Browse files
nbergerdnolen
authored and
dnolen
committed
Avoid corrupted compiler env in ana/parse-ns
parse-ns allows for running the parse in two ways: updating the global compiler env or not updating it. This is controlled via the :restore option. To implement this, it isolates the parsing process by binding the compiler env to a snapshot of the compiler env when it starts. When the parsing is done, it checks the :restore option and if it's false it merges back parts of the resulting compiler env (the ::namespaces and ::constants keys) into the global compiler env. The problem is that during the parsing, other compiler processes could have legitimately updated those same keys in the global compiler env, so this merge can occasionally result in compiler data loss. The race condition can avoided by using a different approach: only when :restore is true the compiler runs isolated from the global compiler env, by taking a snapshot of the env at the beginning. When :restore is false, no snapshot is taken: env/*compiler* binding is not modified, so the global compiler env is mutated in-place
1 parent 4d44548 commit 4e64079

File tree

1 file changed

+21
-27
lines changed

1 file changed

+21
-27
lines changed

src/main/clojure/cljs/analyzer.cljc

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2707,9 +2707,10 @@
27072707
(let [src (if (symbol? src)
27082708
(util/ns->source src)
27092709
src)
2710-
compiler-env @env/*compiler*
2711-
[ijs compiler-env']
2712-
(binding [env/*compiler* (atom compiler-env)
2710+
ijs
2711+
(binding [env/*compiler* (if (false? (:restore opts))
2712+
env/*compiler*
2713+
(atom @env/*compiler*))
27132714
*cljs-ns* 'cljs.user
27142715
*cljs-file* src
27152716
*macro-infer*
@@ -2739,35 +2740,28 @@
27392740
'cljs.core$macros
27402741
ns-name)
27412742
deps (merge (:uses ast) (:requires ast))]
2742-
[(merge
2743-
{:ns (or ns-name 'cljs.user)
2744-
:provides [ns-name]
2745-
:requires (if (= 'cljs.core ns-name)
2746-
(set (vals deps))
2747-
(cond-> (conj (set (vals deps)) 'cljs.core)
2748-
(get-in compiler-env [:options :emit-constants])
2749-
(conj 'constants-table)))
2750-
:file dest
2751-
:source-file (when rdr src)
2752-
:source-forms (when-not rdr src)
2753-
:ast ast
2754-
:macros-ns (or (:macros-ns opts)
2755-
(= 'cljs.core$macros ns-name))}
2756-
(when (and dest (.exists ^File dest))
2757-
{:lines (with-open [reader (io/reader dest)]
2758-
(-> reader line-seq count))}))
2759-
@env/*compiler*])
2743+
(merge
2744+
{:ns (or ns-name 'cljs.user)
2745+
:provides [ns-name]
2746+
:requires (if (= 'cljs.core ns-name)
2747+
(set (vals deps))
2748+
(cond-> (conj (set (vals deps)) 'cljs.core)
2749+
(get-in @env/*compiler* [:options :emit-constants])
2750+
(conj 'constants-table)))
2751+
:file dest
2752+
:source-file (when rdr src)
2753+
:source-forms (when-not rdr src)
2754+
:ast ast
2755+
:macros-ns (or (:macros-ns opts)
2756+
(= 'cljs.core$macros ns-name))}
2757+
(when (and dest (.exists ^File dest))
2758+
{:lines (with-open [reader (io/reader dest)]
2759+
(-> reader line-seq count))})))
27602760
(recur (rest forms))))
27612761
(throw (AssertionError. (str "No ns form found in " src)))))
27622762
(finally
27632763
(when rdr
27642764
(.close ^Reader rdr))))))]
2765-
(when (false? (:restore opts))
2766-
(swap! env/*compiler*
2767-
(fn [old-state]
2768-
(-> old-state
2769-
(update-in [::namespaces] merge (get compiler-env' ::namespaces))
2770-
(update-in [::constant-table] merge (get compiler-env' ::constant-table))))))
27712765
ijs)))))
27722766

27732767
#?(:clj

0 commit comments

Comments
 (0)