diff --git a/compiler+runtime/include/cpp/jank/c_api.h b/compiler+runtime/include/cpp/jank/c_api.h index 099cb587..51c4a02b 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 const 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 86ab89f4..8f382f5b 100644 --- a/compiler+runtime/include/cpp/jank/jit/processor.hpp +++ b/compiler+runtime/include/cpp/jank/jit/processor.hpp @@ -1,11 +1,13 @@ #pragma once +#include #include #include #include #include +#include namespace llvm { @@ -34,11 +36,19 @@ 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 + string_result find_symbol(native_persistent_string const &name) const { - auto const sym(interpreter->getSymbolAddress(name.c_str()).get()); - return sym.toPtr(); + if(auto symbol{ interpreter->getSymbolAddress(name.c_str()) }) + { + return symbol.get().toPtr(); + } + + util::string_builder sb; + sb("Failed for find symbol: '")(name)("'"); + return err(sb.release()); } result diff --git a/compiler+runtime/include/cpp/jank/runtime/context.hpp b/compiler+runtime/include/cpp/jank/runtime/context.hpp index a4d00a8d..ec608040 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 c39ddfb3..01072ac0 100644 --- a/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/core/munge.hpp @@ -5,6 +5,9 @@ namespace jank::runtime { native_persistent_string munge(native_persistent_string const &o); + native_persistent_string munge_extra(native_persistent_string const &o, + native_persistent_string 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/module/loader.hpp b/compiler+runtime/include/cpp/jank/runtime/module/loader.hpp index 53d4d60a..3cab6c7f 100644 --- a/compiler+runtime/include/cpp/jank/runtime/module/loader.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/module/loader.hpp @@ -95,9 +95,6 @@ namespace jank::runtime::module loader(context &rt_ctx, native_persistent_string_view const &ps); - native_bool is_loaded(native_persistent_string_view const &) const; - void set_loaded(native_persistent_string_view const &); - string_result find(native_persistent_string_view const &module, origin const ori); string_result load(native_persistent_string_view const &module, origin const ori); @@ -115,6 +112,5 @@ namespace jank::runtime::module /* This maps module strings to entries. Module strings are like fully qualified Java * class names. */ native_unordered_map entries; - native_set loaded; }; } diff --git a/compiler+runtime/include/cpp/jank/runtime/ns.hpp b/compiler+runtime/include/cpp/jank/runtime/ns.hpp index 8f220676..7814a04c 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 8dbd603c..297c37d9 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(); @@ -255,17 +260,6 @@ namespace clojure::core_native return obj::nil::nil_const(); } - static object_ptr is_module_loaded(object_ptr const path) - { - return make_box(__rt_ctx->module_loader.is_loaded(runtime::to_string(path))); - } - - static object_ptr set_module_loaded(object_ptr const path) - { - __rt_ctx->module_loader.set_loaded(runtime::to_string(path)); - return obj::nil::nil_const(); - } - static object_ptr compile(object_ptr const path) { __rt_ctx->compile_module(runtime::to_string(path)).expect_ok(); @@ -421,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); @@ -465,8 +460,6 @@ jank_object_ptr jank_load_clojure_core_native() intern_fn("alias", &core_native::alias); intern_fn("refer", &core_native::refer); intern_fn("load-module", &core_native::load_module); - intern_fn("set-module-loaded", &core_native::set_module_loaded); - intern_fn("module-loaded?", &core_native::is_module_loaded); intern_fn("compile", &core_native::compile); /* TODO: jank.math? */ diff --git a/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp b/compiler+runtime/src/cpp/jank/analyze/local_frame.cpp index bed1f98a..d5bad793 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 ef965759..69775fdf 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 210fc1cb..5cc9e9cb 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 const 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 df9e1950..439a4027 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,29 @@ namespace jank::codegen { auto const global_ctor_fn(ctx->global_ctor_block->getParent()); ctx->builder->CreateCall(global_ctor_fn, {}); + + /* This dance is performed to keep symbol names unique across all the modules. + * Considering LLVM JIT symbols to be global, we need to define them with + * unique names to avoid conflicts during JIT recompilation/reloading. + * + * The approach, right now, is for each namespace, we will keep a counter + * and will increase it every time we define a new symbol. When we JIT reload + * the same namespace again, we will define new symbols. + * + * This IR codegen for calling `jank_ns_set_symbol_counter`, is to set the counter + * on intial load. + */ + 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 dfa17b77..b1b79bc3 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)); @@ -558,8 +558,10 @@ namespace jank::evaluate __rt_ctx->jit_prc.load_ir_module(std::move(cg_prc.ctx->module), std::move(cg_prc.ctx->llvm_ctx)); - auto const fn(__rt_ctx->jit_prc.find_symbol( - fmt::format("{}_0", munge(cg_prc.root_fn.unique_name)))); + auto const fn( + __rt_ctx->jit_prc + .find_symbol(fmt::format("{}_0", munge(cg_prc.root_fn.unique_name))) + .expect_ok()); return fn(); } } diff --git a/compiler+runtime/src/cpp/jank/jit/processor.cpp b/compiler+runtime/src/cpp/jank/jit/processor.cpp index 63176e62..ac05ca7d 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 f6340559..bae5067b 100644 --- a/compiler+runtime/src/cpp/jank/read/parse.cpp +++ b/compiler+runtime/src/cpp/jank/read/parse.cpp @@ -916,7 +916,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 d5d420e7..a1b95da6 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 native_persistent_string 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 43151033..496afbb9 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 fca56bb6..13fd8029 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,15 @@ namespace jank::runtime return munged; } + native_persistent_string munge_extra(native_persistent_string const &o, + native_persistent_string const &search, + char const * const replace) + { + native_transient_string const ret{ munge(o) }; + std::regex const search_regex{ search.c_str() }; + return std::regex_replace(ret, search_regex, 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/core/seq.cpp b/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp index 6a0ae325..74275d8c 100644 --- a/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/core/seq.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -670,11 +671,7 @@ namespace jank::runtime [&](auto const typed_s) -> native_bool { using S = typename decltype(typed_s)::value_type; - if constexpr(behavior::associatively_readable) - { - return typed_s->contains(key); - } - if constexpr(std::same_as) + if constexpr(behavior::associatively_readable || behavior::set_like) { return typed_s->contains(key); } diff --git a/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp b/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp index bf004367..f742b32d 100644 --- a/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/module/loader.cpp @@ -38,20 +38,14 @@ 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; + static native_persistent_string const dot{ "\\." }; + 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, "_"); + static native_persistent_string const dot{ "\\." }; + std::string ret{ runtime::munge_extra(module, dot, "_") }; return fmt::format("jank_load_{}", ret); } @@ -343,16 +337,6 @@ namespace jank::runtime::module return boost::filesystem::last_write_time(native_transient_string{ source_path }); } - native_bool loader::is_loaded(native_persistent_string_view const &module) const - { - return loaded.contains(module); - } - - void loader::set_loaded(native_persistent_string_view const &module) - { - loaded.emplace(module); - } - string_result loader::find(native_persistent_string_view const &module, origin const ori) { @@ -389,6 +373,7 @@ namespace jank::runtime::module * Unlike class files, object files are tied to the OS, architecture, c++ stdlib etc, * making it hard to share them. */ if(entry->second.o.is_some() && entry->second.o.unwrap().archive_path.is_none() + && entry->second.o.unwrap().exists() && (entry->second.jank.is_some() || entry->second.cljc.is_some())) { auto const o_file_path{ native_transient_string{ entry->second.o.unwrap().path } }; @@ -440,11 +425,6 @@ namespace jank::runtime::module string_result loader::load(native_persistent_string_view const &module, origin const ori) { - if(loader::is_loaded(module)) - { - return ok(); - } - auto const &found_module{ loader::find(module, ori) }; if(found_module.is_err()) { @@ -477,8 +457,6 @@ namespace jank::runtime::module return res; } - loader::set_loaded(module); - return ok(); } @@ -486,6 +464,23 @@ 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) }; + + /* While loading an object, if the main ns loading symbol exists, then + * we don't need to load the object file again. + * + * Existence of the `jank_load_` symbol (also a function), + * means that all the required symbols exist and are already defined. + * We call this symbol to re-initialize all the vars in the namespace. + * */ + auto const load_function_name{ module_to_load_function(module) }; + + auto const existing_load{ rt_ctx.jit_prc.find_symbol(load_function_name) }; + if(existing_load.is_ok()) + { + existing_load.expect_ok()(); + return ok(); + } + if(entry.archive_path.is_some()) { /* TODO: Load object code from string. */ @@ -496,7 +491,7 @@ namespace jank::runtime::module rt_ctx.jit_prc.load_object(entry.path); } - auto const load{ rt_ctx.jit_prc.find_symbol(module_to_load_function(module)) }; + auto const load{ rt_ctx.jit_prc.find_symbol(load_function_name).expect_ok() }; load(); return ok(); diff --git a/compiler+runtime/src/jank/clojure/core.jank b/compiler+runtime/src/jank/clojure/core.jank index 2a4c2983..68ef3a6e 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. @@ -3817,8 +3817,8 @@ (defn- load-all "Loads a lib given its name and forces a load of any libs it directly or - indirectly loads. If need-ns, ensures that the associated namespace - exists after loading. If require, records the load so any duplicate loads + indirectly loads. If need-ns?, ensures that the associated namespace + exists after loading. If require?, records the load so any duplicate loads can be skipped." [lib need-ns? require?] (swap! *loaded-libs* #(reduce conj %1 %2) @@ -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")