diff --git a/compiler+runtime/include/cpp/jank/c_api.h b/compiler+runtime/include/cpp/jank/c_api.h index 099cb587f..2bceb5f26 100644 --- a/compiler+runtime/include/cpp/jank/c_api.h +++ b/compiler+runtime/include/cpp/jank/c_api.h @@ -24,6 +24,8 @@ extern "C" jank_object_ptr jank_eval(jank_object_ptr s); jank_object_ptr jank_read_string(jank_object_ptr s); + void jank_ns_set_symbol_counter(char const * const ns, uint64_t count); + jank_object_ptr jank_var_intern(jank_object_ptr ns, jank_object_ptr name); jank_object_ptr jank_var_bind_root(jank_object_ptr var, jank_object_ptr val); jank_object_ptr jank_var_set_dynamic(jank_object_ptr var, jank_object_ptr dynamic); diff --git a/compiler+runtime/include/cpp/jank/jit/processor.hpp b/compiler+runtime/include/cpp/jank/jit/processor.hpp index 86ab89f42..6865a77ca 100644 --- a/compiler+runtime/include/cpp/jank/jit/processor.hpp +++ b/compiler+runtime/include/cpp/jank/jit/processor.hpp @@ -34,6 +34,8 @@ namespace jank::jit void load_bitcode(native_persistent_string const &module, native_persistent_string_view const &bitcode) const; + string_result remove_symbol(native_persistent_string const &name) const; + template T find_symbol(native_persistent_string const &name) const { diff --git a/compiler+runtime/include/cpp/jank/runtime/context.hpp b/compiler+runtime/include/cpp/jank/runtime/context.hpp index a4d00a8d8..ec6080408 100644 --- a/compiler+runtime/include/cpp/jank/runtime/context.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/context.hpp @@ -107,10 +107,10 @@ namespace jank::runtime /* Generates a unique name for use with anything from codgen structs, * lifted vars, to shadowed locals. */ - static native_persistent_string unique_string(); - static native_persistent_string unique_string(native_persistent_string_view const &prefix); - static obj::symbol unique_symbol(); - static obj::symbol unique_symbol(native_persistent_string_view const &prefix); + native_persistent_string unique_string(); + native_persistent_string unique_string(native_persistent_string_view const &prefix); + obj::symbol unique_symbol(); + obj::symbol unique_symbol(native_persistent_string_view const &prefix); folly::Synchronized> namespaces; folly::Synchronized> keywords; diff --git a/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp b/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp index c39ddfb3e..a6bf6a095 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp @@ -1,10 +1,14 @@ #pragma once +#include #include namespace jank::runtime { native_persistent_string munge(native_persistent_string const &o); + native_persistent_string munge_extra(native_persistent_string const &o, + std::regex const &search, + char const * const replace); object_ptr munge(object_ptr o); native_persistent_string demunge(native_persistent_string const &o); } diff --git a/compiler+runtime/include/cpp/jank/runtime/ns.hpp b/compiler+runtime/include/cpp/jank/runtime/ns.hpp index 8f220676e..7814a04c0 100644 --- a/compiler+runtime/include/cpp/jank/runtime/ns.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/ns.hpp @@ -50,6 +50,8 @@ namespace jank::runtime /* TODO: Benchmark the use of atomics here. That's what Clojure uses. */ folly::Synchronized vars; folly::Synchronized aliases; + + std::atomic_uint64_t symbol_counter{}; context &rt_ctx; }; } diff --git a/compiler+runtime/src/cpp/clojure/core_native.cpp b/compiler+runtime/src/cpp/clojure/core_native.cpp index f388ab290..297c37d9b 100644 --- a/compiler+runtime/src/cpp/clojure/core_native.cpp +++ b/compiler+runtime/src/cpp/clojure/core_native.cpp @@ -78,6 +78,11 @@ namespace clojure::core_native return try_object(o)->deref(); } + static object_ptr intern_var(object_ptr const sym) + { + return __rt_ctx->intern_var(try_object(sym)).expect_ok(); + } + static object_ptr var_get_root(object_ptr const o) { return try_object(o)->get_root(); @@ -410,6 +415,7 @@ jank_object_ptr jank_load_clojure_core_native() intern_fn("namespace", &namespace_); intern_fn("var?", &core_native::is_var); intern_fn("var-get", &core_native::var_get); + intern_fn("intern-var", &core_native::intern_var); intern_fn("var-get-root", &core_native::var_get_root); intern_fn("var-bind-root", &core_native::var_bind_root); intern_fn("alter-var-root", &core_native::alter_var_root); diff --git a/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp b/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp index bed1f98a5..d5bad7931 100644 --- a/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp @@ -248,7 +248,7 @@ namespace jank::analyze return; } - auto const name(context::unique_symbol("const")); + auto const name(__rt_ctx->unique_symbol("const")); auto const unboxed_name{ visit_number_like( [&](auto const) -> option { return obj::symbol{ name.ns, name.name + "__unboxed" }; diff --git a/compiler+runtime/src/cpp/jank/analyze/processor.cpp b/compiler+runtime/src/cpp/jank/analyze/processor.cpp index ef9657598..69775fdf6 100644 --- a/compiler+runtime/src/cpp/jank/analyze/processor.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/processor.cpp @@ -312,7 +312,7 @@ namespace jank::analyze { /* C++ doesn't allow multiple params with the same name, so we generate a unique * name for shared params. */ - param = make_box(runtime::context::unique_string("shadowed")); + param = make_box(__rt_ctx->unique_string("shadowed")); break; } } @@ -387,7 +387,7 @@ namespace jank::analyze { auto const s(runtime::expect_object(first_elem)); name = s->name; - unique_name = runtime::context::unique_string(name); + unique_name = __rt_ctx->unique_string(name); if(length < 3) { return err(error{ fmt::format("fn missing forms: {}", full_list->to_string()) }); @@ -397,7 +397,7 @@ namespace jank::analyze } else { - name = runtime::context::unique_string("fn"); + name = __rt_ctx->unique_string("fn"); unique_name = name; } diff --git a/compiler+runtime/src/cpp/jank/c_api.cpp b/compiler+runtime/src/cpp/jank/c_api.cpp index d0c19181f..c1adde533 100644 --- a/compiler+runtime/src/cpp/jank/c_api.cpp +++ b/compiler+runtime/src/cpp/jank/c_api.cpp @@ -75,9 +75,17 @@ extern "C" return __rt_ctx->read_string(s_obj->data); } + void jank_ns_set_symbol_counter(char const * const ns, uint64_t count) + { + auto const ns_obj(__rt_ctx->intern_ns(ns)); + ns_obj->symbol_counter.store(count); + } + jank_object_ptr jank_var_intern(jank_object_ptr const ns, jank_object_ptr const name) { auto const ns_obj(try_object(reinterpret_cast(ns))); + __rt_ctx->intern_ns(ns_obj->data); + auto const name_obj(try_object(reinterpret_cast(name))); return erase(__rt_ctx->intern_var(ns_obj->data, name_obj->data).expect_ok()); } diff --git a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp index 9258fdea3..77ed57270 100644 --- a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp @@ -26,9 +26,9 @@ namespace jank::codegen reusable_context::reusable_context(native_persistent_string const &module_name) : module_name{ module_name } - , ctor_name{ runtime::munge(runtime::context::unique_string("jank_global_init")) } + , ctor_name{ runtime::munge(__rt_ctx->unique_string("jank_global_init")) } , llvm_ctx{ std::make_unique() } - , module{ std::make_unique(runtime::context::unique_string(module_name).c_str(), + , module{ std::make_unique(__rt_ctx->unique_string(module_name).c_str(), *llvm_ctx) } , builder{ std::make_unique>(*llvm_ctx) } , global_ctor_block{ llvm::BasicBlock::Create(*llvm_ctx, "entry") } @@ -135,6 +135,18 @@ namespace jank::codegen { auto const global_ctor_fn(ctx->global_ctor_block->getParent()); ctx->builder->CreateCall(global_ctor_fn, {}); + + auto const current_ns{ __rt_ctx->current_ns() }; + auto const fn_type( + llvm::FunctionType::get(ctx->builder->getVoidTy(), + { ctx->builder->getPtrTy(), ctx->builder->getInt64Ty() }, + false)); + auto const fn(ctx->module->getOrInsertFunction("jank_ns_set_symbol_counter", fn_type)); + + ctx->builder->CreateCall( + fn, + { gen_c_string(current_ns->name->get_name()), + llvm::ConstantInt::get(ctx->builder->getInt64Ty(), current_ns->symbol_counter.load()) }); } for(size_t i{}; i < arity.params.size(); ++i) diff --git a/compiler+runtime/src/cpp/jank/evaluate.cpp b/compiler+runtime/src/cpp/jank/evaluate.cpp index dfa17b773..c48a2b562 100644 --- a/compiler+runtime/src/cpp/jank/evaluate.cpp +++ b/compiler+runtime/src/cpp/jank/evaluate.cpp @@ -134,7 +134,7 @@ namespace jank::evaluate auto &fn(boost::get>(ret->data)); expr::function_arity arity; fn.name = name; - fn.unique_name = context::unique_string(fn.name); + fn.unique_name = __rt_ctx->unique_string(fn.name); fn.meta = obj::persistent_hash_map::empty(); auto const &closest_fn_frame(local_frame::find_closest_fn_frame(*expr.frame)); diff --git a/compiler+runtime/src/cpp/jank/jit/processor.cpp b/compiler+runtime/src/cpp/jank/jit/processor.cpp index 63176e625..05e421e1f 100644 --- a/compiler+runtime/src/cpp/jank/jit/processor.cpp +++ b/compiler+runtime/src/cpp/jank/jit/processor.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -185,6 +186,20 @@ namespace jank::jit load_ir_module(std::move(ir_module), std::move(ctx)); } + string_result processor::remove_symbol(native_persistent_string const &name) const + { + auto &ee{ interpreter->getExecutionEngine().get() }; + llvm::orc::SymbolNameSet to_remove{}; + to_remove.insert(ee.mangleAndIntern(name.c_str())); + auto const error = ee.getMainJITDylib().remove(to_remove); + + if(error.isA()) + { + return err(fmt::format("Failed to remove the symbol: {}", name)); + } + return ok(); + } + option processor::find_dynamic_lib(native_persistent_string const &lib) const { diff --git a/compiler+runtime/src/cpp/jank/read/parse.cpp b/compiler+runtime/src/cpp/jank/read/parse.cpp index 52bd98d42..0efb8ae77 100644 --- a/compiler+runtime/src/cpp/jank/read/parse.cpp +++ b/compiler+runtime/src/cpp/jank/read/parse.cpp @@ -914,7 +914,7 @@ namespace jank::read::parse auto gensym(get(env, sym)); if(gensym->type == object_type::nil) { - gensym = make_box(context::unique_symbol(sym->name)); + gensym = make_box(__rt_ctx->unique_symbol(sym->name)); __rt_ctx->gensym_env_var->set(assoc(env, sym, gensym)).expect_ok(); } sym = expect_object(gensym); diff --git a/compiler+runtime/src/cpp/jank/runtime/context.cpp b/compiler+runtime/src/cpp/jank/runtime/context.cpp index d5d420e75..cc9da2642 100644 --- a/compiler+runtime/src/cpp/jank/runtime/context.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/context.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -264,7 +266,7 @@ namespace jank::runtime std::make_pair(compile_files_var, obj::boolean::true_const()), std::make_pair(current_module_var, make_box(module))) }; - return load_module(fmt::format("/{}", module), module::origin::source); + return load_module(fmt::format("/{}", module), module::origin::latest); } string_result @@ -285,7 +287,7 @@ namespace jank::runtime module_path.c_str(), file_error.message())); } - //codegen_ctx->module->print(llvm::outs(), nullptr); + // codegen_ctx->module->print(llvm::outs(), nullptr); auto const target_triple{ llvm::sys::getDefaultTargetTriple() }; std::string target_error; @@ -321,8 +323,12 @@ namespace jank::runtime native_persistent_string context::unique_string(native_persistent_string_view const &prefix) { - static std::atomic_size_t index{ 1 }; - return fmt::format(FMT_COMPILE("{}-{}"), prefix.data(), index++); + static std::regex const dot{ "\\." }; + auto const ns{ current_ns() }; + return fmt::format(FMT_COMPILE("{}-{}-{}"), + runtime::munge_extra(ns->name->get_name(), dot, "_"), + prefix.data(), + ++ns->symbol_counter); } obj::symbol context::unique_symbol() diff --git a/compiler+runtime/src/cpp/jank/runtime/core.cpp b/compiler+runtime/src/cpp/jank/runtime/core.cpp index 431510330..496afbb91 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core.cpp @@ -448,7 +448,7 @@ namespace jank::runtime object_ptr gensym(object_ptr const o) { - return make_box(runtime::context::unique_symbol(to_string(o))); + return make_box(__rt_ctx->unique_symbol(to_string(o))); } object_ptr atom(object_ptr const o) diff --git a/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp b/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp index fca56bb69..8d8c52950 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/munge.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -283,6 +285,14 @@ namespace jank::runtime return munged; } + native_persistent_string munge_extra(native_persistent_string const &o, + std::regex const &search, + char const * const replace) + { + std::string ret{ munge(o) }; + return std::regex_replace(ret, search, replace); + } + /* TODO: Support symbols and other data; Clojure takes in anything and passes it through str. */ object_ptr munge(object_ptr const o) { diff --git a/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp b/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp index dfa6bb3a3..3a090fa15 100644 --- a/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp @@ -39,19 +39,13 @@ namespace jank::runtime::module native_persistent_string module_to_path(native_persistent_string_view const &module) { static std::regex const dot{ "\\." }; - - std::string ret{ runtime::munge(module) }; - ret = std::regex_replace(ret, dot, "/"); - - return ret; + return runtime::munge_extra(module, dot, "/"); } native_persistent_string module_to_load_function(native_persistent_string_view const &module) { static std::regex const dot{ "\\." }; - - std::string ret{ runtime::munge(module) }; - ret = std::regex_replace(ret, dot, "_"); + std::string ret{ runtime::munge_extra(module, dot, "_") }; return fmt::format("jank_load_{}", ret); } @@ -469,6 +463,13 @@ namespace jank::runtime::module loader::load_o(native_persistent_string const &module, file_entry const &entry) const { profile::timer const timer{ fmt::format("load object {}", module) }; + auto const res{ rt_ctx.jit_prc.remove_symbol(module_to_load_function(module)) }; + + if(res.is_err()) + { + return res.expect_err(); + } + if(entry.archive_path.is_some()) { /* TODO: Load object code from string. */ diff --git a/compiler+runtime/src/jank/clojure/core.jank b/compiler+runtime/src/jank/clojure/core.jank index f646ee43f..68ef3a6e1 100644 --- a/compiler+runtime/src/jank/clojure/core.jank +++ b/compiler+runtime/src/jank/clojure/core.jank @@ -3638,7 +3638,7 @@ (def find-ns "Returns the namespace named by the symbol or nil if it doesn't exist." - clojure.core-native/create-ns) + clojure.core-native/find-ns) (def remove-ns "Removes the namespace named by the symbol. Use with caution. @@ -3992,13 +3992,32 @@ ~@(when (and (not= name 'clojure.core) refer-full-clojure?) `((clojure.core/refer '~'clojure.core))) ~@(map process-reference references)) - (if (= '~name 'clojure.core) + (if (= '~name '~'clojure.core) nil - (do (swap! *loaded-libs* conj '~name) nil))))) + (do (swap! @#'*loaded-libs* conj '~name) nil))))) (defmacro refer-clojure "Same as (refer 'clojure.core )" [& filters] `(clojure.core/refer '~'clojure.core ~@filters)) +(defn intern + "Finds or creates a var named by the symbol name in the namespace + ns (which can be a symbol or a namespace), setting its root binding + to val if supplied. The namespace must exist. The var will adopt any + metadata from the name symbol. Returns the var." + ([ns name] + (let [v (clojure.core-native/intern-var + (clojure.core-native/->qualified-symbol + (the-ns ns) name))] + (when (meta name) (clojure.core-native/reset-meta! v (meta name))) + v)) + ([ns name val] + (let [v (clojure.core-native/intern-var + (clojure.core-native/->qualified-symbol + (the-ns ns) name))] + (clojure.core-native/var-bind-root v val) + (when (meta name) (clojure.core-native/reset-meta! v (meta name))) + v))) + (println "Bottom of clojure.core")