Problem
MAGIC has two namespace-loading paths that do not share state about what is loaded:
- C#
Assembly.LoadFrom + RT.TryLoadInitType via Nostrand.cs BootClojureAndNostrand, which bypasses clojure.core/load-lib.
- Clojure
load-lib -> load-one -> -load-assembly, which is the only path that conjes onto *loaded-libs*.
The ns macro bridges them for non-core namespaces (each one self-registers as its ns form runs). clojure.core is handled by an explicit *loaded-libs* seed in core.clj (#2). But any stray Assembly.LoadFrom + InitAssembly on an already-loaded namespace would still re-run every top-level form in it, including the def of *load-paths* at magic-compiler/src/stdlib/clojure/core.clj ~line 5855. That re-runs the load-path reset and cascades into sub-namespace re-loads.
Compiler.InitAssembly in clojure-runtime/Clojure/CljCompiler/Compiler.cs (~line 1749) currently has no idempotency guard. It calls InvokeInitType unconditionally.
Suggestion
Track initialized init-types in a static HashSet<Type> in Compiler.cs. Short-circuit re-entry in InvokeInitType when the type has already been invoked. Pin down the bootstrap protocol so the *loaded-libs* seed in core.clj becomes redundant rather than load-bearing.
Problem
MAGIC has two namespace-loading paths that do not share state about what is loaded:
Assembly.LoadFrom+RT.TryLoadInitTypeviaNostrand.csBootClojureAndNostrand, which bypassesclojure.core/load-lib.load-lib->load-one->-load-assembly, which is the only path that conjes onto*loaded-libs*.The
nsmacro bridges them for non-core namespaces (each one self-registers as itsnsform runs).clojure.coreis handled by an explicit*loaded-libs*seed incore.clj(#2). But any strayAssembly.LoadFrom+InitAssemblyon an already-loaded namespace would still re-run every top-level form in it, including thedefof*load-paths*atmagic-compiler/src/stdlib/clojure/core.clj~line 5855. That re-runs the load-path reset and cascades into sub-namespace re-loads.Compiler.InitAssemblyinclojure-runtime/Clojure/CljCompiler/Compiler.cs(~line 1749) currently has no idempotency guard. It callsInvokeInitTypeunconditionally.Suggestion
Track initialized init-types in a static
HashSet<Type>inCompiler.cs. Short-circuit re-entry inInvokeInitTypewhen the type has already been invoked. Pin down the bootstrap protocol so the*loaded-libs*seed incore.cljbecomes redundant rather than load-bearing.