From dfca529319e1f7ff68962b9c677949d4f7f69e47 Mon Sep 17 00:00:00 2001 From: jeaye Date: Thu, 16 Oct 2025 12:55:17 -0700 Subject: [PATCH 1/7] Explicitly set bdwgc debug flags --- compiler+runtime/cmake/dependency/bdwgc.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler+runtime/cmake/dependency/bdwgc.cmake b/compiler+runtime/cmake/dependency/bdwgc.cmake index fff5b9cba..26706a9f1 100644 --- a/compiler+runtime/cmake/dependency/bdwgc.cmake +++ b/compiler+runtime/cmake/dependency/bdwgc.cmake @@ -11,11 +11,15 @@ set(CMAKE_CXX_CLANG_TIDY_OLD ${CMAKE_CXX_CLANG_TIDY}) set(enable_docs OFF CACHE BOOL "Enable docs") set(enable_large_config ON CACHE BOOL "Optimize for large heap or root set") set(enable_throw_bad_alloc_library ON CACHE BOOL "Enable C++ gctba library build") + set(enable_gc_debug OFF CACHE BOOL "Support for pointer back-tracing") add_subdirectory(third-party/bdwgc EXCLUDE_FROM_ALL) unset(enable_cplusplus) unset(build_cord) unset(enable_docs) + unset(enable_large_config) + unset(enable_throw_bad_alloc_library) + unset(enable_gc_debug) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_OLD}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}") set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_OLD}) From bf31860d7106b98ed02c4bb27c7983e73fb77387 Mon Sep 17 00:00:00 2001 From: jeaye Date: Thu, 16 Oct 2025 12:56:30 -0700 Subject: [PATCH 2/7] Move reusable_context to jtl::ref --- .../cpp/jank/codegen/llvm_processor.hpp | 2 +- .../src/cpp/jank/codegen/llvm_processor.cpp | 39 ++++++------------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp b/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp index c2bb669c6..123969dc1 100644 --- a/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp +++ b/compiler+runtime/include/cpp/jank/codegen/llvm_processor.hpp @@ -94,7 +94,7 @@ namespace jank::codegen compilation_target target); /* For this ctor, we're inheriting the context from another function, which means * we're building a nested function. */ - llvm_processor(analyze::expr::function_ref expr, std::unique_ptr ctx); + llvm_processor(analyze::expr::function_ref expr, jtl::ref ctx); llvm_processor(llvm_processor const &) = delete; llvm_processor(llvm_processor &&) noexcept = default; diff --git a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp index 05eef930f..c55e2f48e 100644 --- a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp @@ -88,7 +88,7 @@ namespace jank::codegen compilation_target target); /* For this ctor, we're inheriting the context from another function, which means * we're building a nested function. */ - impl(analyze::expr::function_ref expr, std::unique_ptr ctx); + impl(analyze::expr::function_ref expr, jtl::ref ctx); jtl::string_result gen(); llvm::Value *gen(analyze::expression_ref, analyze::expr::function_arity const &); @@ -181,10 +181,9 @@ namespace jank::codegen compilation_target target{}; analyze::expr::function_ref root_fn; jtl::ptr fn{}; - std::unique_ptr ctx; + jtl::ref ctx; native_unordered_map> locals; - /* TODO: Use gc allocator to avoid leaks. */ - std::list deferred_inits{}; + native_list deferred_inits{}; jtl::ref llvm_ctx; jtl::ref llvm_module; jtl::ptr current_loop; @@ -479,9 +478,8 @@ namespace jank::codegen /* Whenever we have an object in an `alloca`, we need to load it before using. This fn only * makes sense to use with jank objects, as opposed to native values. */ - static llvm::Value *load_if_needed(std::unique_ptr const &ctx, - llvm::Value *arg, - jtl::ptr const type) + static llvm::Value * + load_if_needed(jtl::ref const ctx, llvm::Value *arg, jtl::ptr const type) { if(!arg) { @@ -495,8 +493,7 @@ namespace jank::codegen return arg; } - static llvm::Value * - load_if_needed(std::unique_ptr const &ctx, llvm::Value * const arg) + static llvm::Value *load_if_needed(jtl::ref const ctx, llvm::Value * const arg) { return load_if_needed(ctx, arg, cpp_util::untyped_object_ptr_type()); } @@ -576,8 +573,8 @@ namespace jank::codegen } llvm_processor::llvm_processor(expr::function_ref const expr, - std::unique_ptr ctx) - : _impl{ make_ref(expr, jtl::move(ctx)) } + jtl::ref const ctx) + : _impl{ make_ref(expr, ctx) } { } @@ -586,13 +583,13 @@ namespace jank::codegen compilation_target const target) : target{ target } , root_fn{ expr } - , ctx{ std::make_unique(module_name, std::make_unique()) } + , ctx{ make_ref(module_name, std::make_unique()) } , llvm_ctx{ extract_context(ctx->module) } , llvm_module{ ctx->module.getModuleUnlocked() } { } - llvm_processor::impl::impl(expr::function_ref const expr, std::unique_ptr ctx) + llvm_processor::impl::impl(expr::function_ref const expr, jtl::ref ctx) : target{ compilation_target::function } , root_fn{ expr } , ctx{ std::move(ctx) } @@ -1147,27 +1144,13 @@ namespace jank::codegen { llvm::IRBuilder<>::InsertPointGuard const guard{ *ctx->builder }; - llvm_processor nested{ expr, std::move(ctx) }; - - /* We need to make sure to transfer ownership of the context back, even if an exception - * is thrown. */ - util::scope_exit const finally{ [&]() { - if(nested._impl->ctx) - { - ctx = std::move(nested._impl->ctx); - } - } }; - + llvm_processor nested{ expr, ctx }; auto const res{ nested.gen() }; if(res.is_err()) { /* TODO: Return error. */ res.expect_ok(); } - - /* This is covered by finally, but clang-tidy can't figure that out, so we have - * to make this more clear. */ - ctx = std::move(nested._impl->ctx); } auto const fn_obj(gen_function_instance(expr, fn_arity)); From b8f24b53e4e955692fddbd8f73c3ff6f4b3ddcdc Mon Sep 17 00:00:00 2001 From: jeaye Date: Thu, 16 Oct 2025 12:57:06 -0700 Subject: [PATCH 3/7] Use gc allocator and remove thread_local usage --- .../include/cpp/jank/read/parse.hpp | 2 +- .../include/cpp/jank/runtime/context.hpp | 5 ++--- .../src/cpp/jank/analyze/processor.cpp | 2 +- .../src/cpp/jank/runtime/context.cpp | 17 ++++++----------- compiler+runtime/src/cpp/jank/runtime/var.cpp | 2 +- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/compiler+runtime/include/cpp/jank/read/parse.hpp b/compiler+runtime/include/cpp/jank/read/parse.hpp index 8de1c5e14..e42d364d4 100644 --- a/compiler+runtime/include/cpp/jank/read/parse.hpp +++ b/compiler+runtime/include/cpp/jank/read/parse.hpp @@ -117,7 +117,7 @@ namespace jank::read::parse * token, we should check this list to see if there's already a form we should pull out. * This is needed because parse iteration works one form at a time and splicing potentially * turns one form into many. */ - std::list pending_forms; + native_list pending_forms; lex::token latest_token; jtl::option shorthand; /* Whether or not the next form is considered quoted. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/context.hpp b/compiler+runtime/include/cpp/jank/runtime/context.hpp index 353b17fcf..d6661e10e 100644 --- a/compiler+runtime/include/cpp/jank/runtime/context.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/context.hpp @@ -43,7 +43,6 @@ namespace jank::runtime context(); context(context const &) = delete; context(context &&) noexcept = delete; - ~context(); ns_ref intern_ns(jtl::immutable_string const &); ns_ref intern_ns(obj::symbol_ref const &); @@ -162,8 +161,8 @@ namespace jank::runtime /* Hold onto the CLI Options for use at runtime */ util::cli::options opts; - /* TODO: Remove this map. Just use the list. */ - static thread_local native_unordered_map> + /* XXX: We can't use thread_local here, due to bdwgc not supporting it. */ + static native_unordered_map> thread_binding_frames; /* This must go last, since it'll try to access other bits in the runtime context during diff --git a/compiler+runtime/src/cpp/jank/analyze/processor.cpp b/compiler+runtime/src/cpp/jank/analyze/processor.cpp index 1ece62ee9..e0408cf1a 100644 --- a/compiler+runtime/src/cpp/jank/analyze/processor.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/processor.cpp @@ -1632,7 +1632,7 @@ namespace jank::analyze native_vector param_symbols; param_symbols.reserve(params->data.size()); - std::set unique_param_symbols; + native_set unique_param_symbols; bool is_variadic{}; for(auto it(params->data.begin()); it != params->data.end(); ++it) diff --git a/compiler+runtime/src/cpp/jank/runtime/context.cpp b/compiler+runtime/src/cpp/jank/runtime/context.cpp index 4eea03e64..4af42365a 100644 --- a/compiler+runtime/src/cpp/jank/runtime/context.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/context.cpp @@ -34,7 +34,7 @@ namespace jank::runtime { /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ - thread_local decltype(context::thread_binding_frames) context::thread_binding_frames{}; + decltype(context::thread_binding_frames) context::thread_binding_frames{}; /* NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) */ context *__rt_ctx{}; @@ -93,11 +93,6 @@ namespace jank::runtime .expect_ok(); } - context::~context() - { - thread_binding_frames.erase(this); - } - obj::symbol_ref context::qualify_symbol(obj::symbol_ref const &sym) const { obj::symbol_ref qualified_sym{ sym }; @@ -708,7 +703,7 @@ namespace jank::runtime jtl::string_result context::push_thread_bindings() { auto bindings(obj::persistent_hash_map::empty()); - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames[std::this_thread::get_id()]); if(!tbfs.empty()) { bindings = tbfs.front().bindings; @@ -737,7 +732,7 @@ namespace jank::runtime context::push_thread_bindings(obj::persistent_hash_map_ref const bindings) { thread_binding_frame frame{ obj::persistent_hash_map::empty() }; - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames[std::this_thread::get_id()]); if(!tbfs.empty()) { frame.bindings = tbfs.front().bindings; @@ -780,7 +775,7 @@ namespace jank::runtime jtl::string_result context::pop_thread_bindings() { - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames[std::this_thread::get_id()]); if(tbfs.empty()) { return err("Mismatched thread binding pop"); @@ -793,7 +788,7 @@ namespace jank::runtime obj::persistent_hash_map_ref context::get_thread_bindings() const { - auto const &tbfs(thread_binding_frames[this]); + auto const &tbfs(thread_binding_frames[std::this_thread::get_id()]); if(tbfs.empty()) { return obj::persistent_hash_map::empty(); @@ -803,7 +798,7 @@ namespace jank::runtime jtl::option context::current_thread_binding_frame() { - auto &tbfs(thread_binding_frames[this]); + auto &tbfs(thread_binding_frames[std::this_thread::get_id()]); if(tbfs.empty()) { return none; diff --git a/compiler+runtime/src/cpp/jank/runtime/var.cpp b/compiler+runtime/src/cpp/jank/runtime/var.cpp index 44f739671..aea909fc9 100644 --- a/compiler+runtime/src/cpp/jank/runtime/var.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/var.cpp @@ -150,7 +150,7 @@ namespace jank::runtime return {}; } - auto &tbfs(__rt_ctx->thread_binding_frames[__rt_ctx]); + auto &tbfs(__rt_ctx->thread_binding_frames[std::this_thread::get_id()]); if(tbfs.empty()) { return {}; From c538cd5582f124e2b39aa2053046afa43e4c9b8e Mon Sep 17 00:00:00 2001 From: jeaye Date: Thu, 16 Oct 2025 16:58:02 -0700 Subject: [PATCH 4/7] Upgrade bdwgc and use malloc redirection This currently doesn't work with ASan, but I have an open issue for this here: https://github.com/bdwgc/bdwgc/issues/772 --- compiler+runtime/CMakeLists.txt | 1 + compiler+runtime/cmake/dependency/bdwgc.cmake | 11 +++++++++-- compiler+runtime/src/cpp/jank/c_api.cpp | 1 - compiler+runtime/src/cpp/jank/read/lex.cpp | 2 +- compiler+runtime/src/cpp/jank/read/parse.cpp | 12 ++++++------ compiler+runtime/src/cpp/jank/runtime/context.cpp | 2 +- .../cpp/jank/runtime/obj/native_vector_sequence.cpp | 6 +++--- compiler+runtime/third-party/bdwgc | 2 +- 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/compiler+runtime/CMakeLists.txt b/compiler+runtime/CMakeLists.txt index 4eefdd793..1272533a2 100644 --- a/compiler+runtime/CMakeLists.txt +++ b/compiler+runtime/CMakeLists.txt @@ -42,6 +42,7 @@ option(jank_coverage "Enable code coverage measurement" OFF) option(jank_analyze "Enable static analysis" OFF) option(jank_test "Enable jank's test suite" OFF) option(jank_unity_build "Optimize translation unit compilation for the number of cores" OFF) +option(jank_debug_gc "Enable GC debug assertions" OFF) set(jank_sanitize "none" CACHE STRING "The type of Clang sanitization to use (or none)") set(jank_resource_dir "../lib/jank/${CMAKE_PROJECT_VERSION}" diff --git a/compiler+runtime/cmake/dependency/bdwgc.cmake b/compiler+runtime/cmake/dependency/bdwgc.cmake index 26706a9f1..a0b897c78 100644 --- a/compiler+runtime/cmake/dependency/bdwgc.cmake +++ b/compiler+runtime/cmake/dependency/bdwgc.cmake @@ -2,8 +2,8 @@ set(CMAKE_C_FLAGS_OLD "${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS_OLD "${CMAKE_CXX_FLAGS}") set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS}) set(CMAKE_CXX_CLANG_TIDY_OLD ${CMAKE_CXX_CLANG_TIDY}) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w -DREDIRECT_MALLOC=GC_malloc_uncollectable") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w -DREDIRECT_MALLOC=GC_malloc_uncollectable") set(BUILD_SHARED_LIBS OFF) set(CMAKE_CXX_CLANG_TIDY "") set(enable_cplusplus ON CACHE BOOL "Enable C++") @@ -12,6 +12,13 @@ set(CMAKE_CXX_CLANG_TIDY_OLD ${CMAKE_CXX_CLANG_TIDY}) set(enable_large_config ON CACHE BOOL "Optimize for large heap or root set") set(enable_throw_bad_alloc_library ON CACHE BOOL "Enable C++ gctba library build") set(enable_gc_debug OFF CACHE BOOL "Support for pointer back-tracing") + + if(jank_debug_gc) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGC_ASSERTIONS") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGC_ASSERTIONS") + set(enable_gc_debug ON CACHE BOOL "Support for pointer back-tracing") + endif() + add_subdirectory(third-party/bdwgc EXCLUDE_FROM_ALL) unset(enable_cplusplus) diff --git a/compiler+runtime/src/cpp/jank/c_api.cpp b/compiler+runtime/src/cpp/jank/c_api.cpp index b6f317a33..ac766ee0c 100644 --- a/compiler+runtime/src/cpp/jank/c_api.cpp +++ b/compiler+runtime/src/cpp/jank/c_api.cpp @@ -1017,7 +1017,6 @@ extern "C" /* The GC needs to enabled even before arg parsing, since our native types, * like strings, use the GC for allocations. It can still be configured later. */ GC_set_all_interior_pointers(1); - GC_enable(); GC_init(); llvm::llvm_shutdown_obj const Y{}; diff --git a/compiler+runtime/src/cpp/jank/read/lex.cpp b/compiler+runtime/src/cpp/jank/read/lex.cpp index dd71dab54..1e8339cce 100644 --- a/compiler+runtime/src/cpp/jank/read/lex.cpp +++ b/compiler+runtime/src/cpp/jank/read/lex.cpp @@ -1081,7 +1081,7 @@ namespace jank::read::lex return error::lex_invalid_number( util::format( "Characters '{}' are invalid for a base {} number.", - jtl::immutable_string_view{ invalid_digits.begin(), invalid_digits.end() }, + jtl::immutable_string_view{ invalid_digits.data(), invalid_digits.size() }, radix), { token_start, pos }); } diff --git a/compiler+runtime/src/cpp/jank/read/parse.cpp b/compiler+runtime/src/cpp/jank/read/parse.cpp index 4ca0535b8..40f2cdc20 100644 --- a/compiler+runtime/src/cpp/jank/read/parse.cpp +++ b/compiler+runtime/src/cpp/jank/read/parse.cpp @@ -409,7 +409,7 @@ namespace jank::read::parse parsed_keys.insert({ key.ptr, key }); - if constexpr(std::same_as) + if constexpr(jtl::is_same) { map.insert_or_assign(key.ptr, value.unwrap().ptr); } @@ -435,7 +435,7 @@ namespace jank::read::parse return object_source_info{ make_box( source_to_meta(start_token.start, latest_token.end), - std::move(map)), + jtl::move(map)), start_token, latest_token }; } @@ -453,7 +453,7 @@ namespace jank::read::parse return object_source_info{ make_box( source_to_meta(start_token.start, latest_token.end), - std::move(map)), + jtl::move(map)), start_token, latest_token }; } @@ -538,7 +538,7 @@ namespace jank::read::parse auto meta_result(visit_object( [&](auto const typed_val) -> processor::object_result { using T = typename decltype(typed_val)::value_type; - if constexpr(std::same_as) + if constexpr(jtl::is_same) { return object_source_info{ obj::persistent_array_map::create_unique(typed_val, jank_true), start_token, @@ -683,7 +683,7 @@ namespace jank::read::parse expected_closer = prev_expected_closer; return object_source_info{ make_box( source_to_meta(start_token.start, latest_token.end), - std::move(ret).persistent()), + jtl::move(ret).persistent()), start_token, latest_token }; } @@ -1285,7 +1285,7 @@ namespace jank::read::parse [&](auto const typed_form) -> jtl::result { using T = typename decltype(typed_form)::value_type; - if constexpr(std::same_as) + if constexpr(jtl::is_same) { auto const seq(typed_form->seq()); if(seq.is_nil()) diff --git a/compiler+runtime/src/cpp/jank/runtime/context.cpp b/compiler+runtime/src/cpp/jank/runtime/context.cpp index 4af42365a..24bb7c1dc 100644 --- a/compiler+runtime/src/cpp/jank/runtime/context.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/context.cpp @@ -186,7 +186,7 @@ namespace jank::runtime auto const name{ module::module_to_load_function(module) }; auto const form{ runtime::conj( - runtime::conj(runtime::conj(make_box(std::move(forms)), + runtime::conj(runtime::conj(make_box(jtl::move(forms)), obj::persistent_vector::empty()), make_box(name)), make_box("fn*")) }; diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp index 7603e8e3e..cea169687 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/native_vector_sequence.cpp @@ -12,13 +12,13 @@ namespace jank::runtime::obj } native_vector_sequence::native_vector_sequence(native_vector &&data) - : data{ std::move(data) } + : data{ jtl::move(data) } { jank_debug_assert(!this->data.empty()); } native_vector_sequence::native_vector_sequence(native_vector &&data, usize index) - : data{ std::move(data) } + : data{ jtl::move(data) } , index{ index } { jank_debug_assert(!this->data.empty()); @@ -26,7 +26,7 @@ namespace jank::runtime::obj native_vector_sequence::native_vector_sequence(jtl::option const &meta, native_vector &&data) - : data{ std::move(data) } + : data{ jtl::move(data) } , meta{ meta } { } diff --git a/compiler+runtime/third-party/bdwgc b/compiler+runtime/third-party/bdwgc index 88a61fc6f..19a7f495c 160000 --- a/compiler+runtime/third-party/bdwgc +++ b/compiler+runtime/third-party/bdwgc @@ -1 +1 @@ -Subproject commit 88a61fc6f2688d8e1ea94f3f810c23db89a3f30b +Subproject commit 19a7f495cd7c48cdf6f56c593c6dd57187afa079 From 238cfdbee3ca9161e6d0f4fcd9021955fdc650e0 Mon Sep 17 00:00:00 2001 From: jeaye Date: Thu, 16 Oct 2025 17:56:16 -0700 Subject: [PATCH 5/7] Fix clang-tidy issues --- compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp | 2 +- compiler+runtime/src/cpp/jank/runtime/var.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp index c55e2f48e..1f4666a6d 100644 --- a/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp +++ b/compiler+runtime/src/cpp/jank/codegen/llvm_processor.cpp @@ -1144,7 +1144,7 @@ namespace jank::codegen { llvm::IRBuilder<>::InsertPointGuard const guard{ *ctx->builder }; - llvm_processor nested{ expr, ctx }; + llvm_processor const nested{ expr, ctx }; auto const res{ nested.gen() }; if(res.is_err()) { diff --git a/compiler+runtime/src/cpp/jank/runtime/var.cpp b/compiler+runtime/src/cpp/jank/runtime/var.cpp index aea909fc9..8894d37e8 100644 --- a/compiler+runtime/src/cpp/jank/runtime/var.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/var.cpp @@ -150,7 +150,7 @@ namespace jank::runtime return {}; } - auto &tbfs(__rt_ctx->thread_binding_frames[std::this_thread::get_id()]); + auto &tbfs(runtime::context::thread_binding_frames[std::this_thread::get_id()]); if(tbfs.empty()) { return {}; From 0c6bfe16d242cda64e5f50358be3fcf3837ad2d6 Mon Sep 17 00:00:00 2001 From: jeaye Date: Wed, 5 Nov 2025 11:41:01 -0800 Subject: [PATCH 6/7] Remove BppTree It leaks, leads to premature GC, takes too long to compile, and doesn't support runtime sorting functions. We'll need a new solution. For now, we're deep copying standard containers, which isn't going to last us very long. --- .../include/cpp/jank/runtime/detail/type.hpp | 27 ++++++------------- .../jank/runtime/obj/transient_sorted_map.hpp | 3 +-- .../jank/runtime/obj/transient_sorted_set.hpp | 3 +-- compiler+runtime/include/cpp/jank/type.hpp | 2 +- .../src/cpp/jank/analyze/processor.cpp | 17 +----------- .../src/cpp/jank/runtime/detail/type.cpp | 8 ------ .../runtime/obj/persistent_sorted_map.cpp | 12 +++++---- .../runtime/obj/persistent_sorted_set.cpp | 18 +++++++------ .../jank/runtime/obj/transient_sorted_map.cpp | 15 ++++------- .../jank/runtime/obj/transient_sorted_set.cpp | 26 +++++++----------- compiler+runtime/third-party/bpptree | 1 - 11 files changed, 44 insertions(+), 88 deletions(-) delete mode 160000 compiler+runtime/third-party/bpptree diff --git a/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp b/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp index 8eab57d00..a115e6602 100644 --- a/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/detail/type.hpp @@ -8,9 +8,6 @@ #include #include -#include -#include - #include #include @@ -36,15 +33,6 @@ namespace immer jank::memory_policy>; } -namespace bpptree::detail -{ - extern template struct BppTreeSet; - extern template struct BppTreeMap; -} - namespace jank::runtime::detail { using native_persistent_vector = immer::vector; @@ -54,11 +42,10 @@ namespace jank::runtime::detail set, std::equal_to, memory_policy>; using native_transient_hash_set = native_persistent_hash_set::transient_type; - /* TODO: These BppTree types will leak until we get them GC allocated. */ + /* TODO: Bring in proper immutable sorted maps/sets. */ using native_persistent_sorted_set - = bpptree::BppTreeSet::Persistent; - using native_transient_sorted_set - = bpptree::BppTreeSet::Transient; + = std::set>; + using native_transient_sorted_set = native_persistent_sorted_set; using native_persistent_hash_map = immer::map::Persistent; - using native_transient_sorted_map - = bpptree::BppTreeMap::Transient; + = std::map>>; + using native_transient_sorted_map = native_persistent_sorted_map; /* If an object requires this in its constructor, use your runtime context to intern * it instead. */ diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp index 97e3fdcc1..5b77e1145 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_map.hpp @@ -18,8 +18,7 @@ namespace jank::runtime::obj transient_sorted_map() = default; transient_sorted_map(transient_sorted_map &&) noexcept = default; transient_sorted_map(transient_sorted_map const &) = default; - transient_sorted_map(runtime::detail::native_persistent_sorted_map const &d); - transient_sorted_map(runtime::detail::native_persistent_sorted_map &&d); + transient_sorted_map(value_type const &d); transient_sorted_map(value_type &&d); static transient_sorted_map_ref empty(); diff --git a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp index e2d679eaf..1f05fab0b 100644 --- a/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp +++ b/compiler+runtime/include/cpp/jank/runtime/obj/transient_sorted_set.hpp @@ -18,8 +18,7 @@ namespace jank::runtime::obj transient_sorted_set() = default; transient_sorted_set(transient_sorted_set &&) noexcept = default; transient_sorted_set(transient_sorted_set const &) = default; - transient_sorted_set(runtime::detail::native_persistent_sorted_set const &d); - transient_sorted_set(runtime::detail::native_persistent_sorted_set &&d); + transient_sorted_set(value_type const &d); transient_sorted_set(value_type &&d); static transient_sorted_set_ref empty(); diff --git a/compiler+runtime/include/cpp/jank/type.hpp b/compiler+runtime/include/cpp/jank/type.hpp index dbd3eef3a..0fb35c802 100644 --- a/compiler+runtime/include/cpp/jank/type.hpp +++ b/compiler+runtime/include/cpp/jank/type.hpp @@ -43,7 +43,7 @@ namespace jank template using native_list = std::list>; template - using native_map = std::map>>; + using native_map = std::map, native_allocator>>; template using native_set = std::set, native_allocator>; diff --git a/compiler+runtime/src/cpp/jank/analyze/processor.cpp b/compiler+runtime/src/cpp/jank/analyze/processor.cpp index aba6ec9af..95ddfe3ff 100644 --- a/compiler+runtime/src/cpp/jank/analyze/processor.cpp +++ b/compiler+runtime/src/cpp/jank/analyze/processor.cpp @@ -2884,27 +2884,12 @@ namespace jank::analyze /* TODO: Detect literal and act accordingly. */ return visit_map_like( [&](auto const typed_o) -> processor::expression_result { - using T = typename decltype(typed_o)::value_type; - native_vector> exprs; exprs.reserve(typed_o->data.size()); for(auto const &kv : typed_o->data) { - /* The two maps (hash and sorted) have slightly different iterators, so we need to - * pull out the entries differently. */ - object_ref first{}, second{}; - if constexpr(std::same_as) - { - auto const &entry(kv.get()); - first = entry.first; - second = entry.second; - } - else - { - first = kv.first; - second = kv.second; - } + object_ref const first{ kv.first }, second{ kv.second }; auto k_expr(analyze(first, current_frame, expression_position::value, fn_ctx, true)); if(k_expr.is_err()) diff --git a/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp b/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp index cd8a24c82..b8c4abafd 100644 --- a/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/detail/type.cpp @@ -22,11 +22,3 @@ namespace immer std::equal_to, jank::memory_policy>; } - -namespace bpptree::detail -{ - template struct BppTreeSet; - template struct BppTreeMap; -} diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp index 23fbbea2d..212a26131 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_map.cpp @@ -56,9 +56,9 @@ namespace jank::runtime::obj typed_seq->to_string()) }; } auto const val(*it); - transient.insert_or_assign(key, val); + transient[key] = val; } - return transient.persistent(); + return transient; } else { @@ -100,19 +100,21 @@ namespace jank::runtime::obj bool persistent_sorted_map::contains(object_ref const key) const { - return data.find(key) != data.end(); + return data.contains(key); } persistent_sorted_map_ref persistent_sorted_map::assoc(object_ref const key, object_ref const val) const { - auto copy(data.insert_or_assign(key, val)); + auto copy(data); + copy[key] = val; return make_box(meta, std::move(copy)); } persistent_sorted_map_ref persistent_sorted_map::dissoc(object_ref const key) const { - auto copy(data.erase_key(key)); + auto copy(data); + copy.erase(key); return make_box(meta, std::move(copy)); } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp index 2516fc267..283d1bef3 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/persistent_sorted_set.cpp @@ -41,9 +41,9 @@ namespace jank::runtime::obj runtime::detail::native_transient_sorted_set transient; for(auto const e : make_sequence_range(typed_seq)) { - transient.insert_v(e); + transient.insert(e); } - return transient.persistent(); + return transient; }, seq)); } @@ -130,8 +130,9 @@ namespace jank::runtime::obj persistent_sorted_set_ref persistent_sorted_set::conj(object_ref const head) const { - auto set(data.insert_v(head)); - auto ret(make_box(meta, std::move(set))); + auto copy(data); + copy.insert(head); + auto ret(make_box(meta, std::move(copy))); return ret; } @@ -140,7 +141,7 @@ namespace jank::runtime::obj auto const found(data.find(o)); if(found != data.end()) { - return found.get(); + return *found; } return jank_nil; } @@ -152,13 +153,14 @@ namespace jank::runtime::obj bool persistent_sorted_set::contains(object_ref const o) const { - return data.find(o) != data.end(); + return data.contains(o); } persistent_sorted_set_ref persistent_sorted_set::disj(object_ref const o) const { - auto set(data.erase_key(o)); - auto ret(make_box(meta, std::move(set))); + auto copy(data); + copy.erase(o); + auto ret(make_box(meta, std::move(copy))); return ret; } } diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp index 7fbb68553..0629d1c22 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_map.cpp @@ -9,17 +9,12 @@ namespace jank::runtime::obj { - transient_sorted_map::transient_sorted_map(runtime::detail::native_persistent_sorted_map &&d) - : data{ std::move(d).transient() } - { - } - transient_sorted_map::transient_sorted_map(runtime::detail::native_persistent_sorted_map const &d) - : data{ d.transient() } + : data{ d } { } - transient_sorted_map::transient_sorted_map(runtime::detail::native_transient_sorted_map &&d) + transient_sorted_map::transient_sorted_map(runtime::detail::native_persistent_sorted_map &&d) : data{ std::move(d) } { } @@ -107,14 +102,14 @@ namespace jank::runtime::obj transient_sorted_map::assoc_in_place(object_ref const key, object_ref const val) { assert_active(); - data.insert_or_assign(key, val); + data[key] = val; return this; } transient_sorted_map_ref transient_sorted_map::dissoc_in_place(object_ref const key) { assert_active(); - data.erase_key(key); + data.erase(key); return this; } @@ -151,7 +146,7 @@ namespace jank::runtime::obj { assert_active(); active = false; - return make_box(std::move(data).persistent()); + return make_box(std::move(data)); } object_ref transient_sorted_map::call(object_ref const o) const diff --git a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp index 0e92a615a..1aa04f45b 100644 --- a/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp +++ b/compiler+runtime/src/cpp/jank/runtime/obj/transient_sorted_set.cpp @@ -6,17 +6,12 @@ namespace jank::runtime::obj { - transient_sorted_set::transient_sorted_set(runtime::detail::native_persistent_sorted_set &&d) - : data{ std::move(d).transient() } - { - } - transient_sorted_set::transient_sorted_set(runtime::detail::native_persistent_sorted_set const &d) - : data{ d.transient() } + : data{ d } { } - transient_sorted_set::transient_sorted_set(runtime::detail::native_transient_sorted_set &&d) + transient_sorted_set::transient_sorted_set(runtime::detail::native_persistent_sorted_set &&d) : data{ std::move(d) } { } @@ -64,7 +59,7 @@ namespace jank::runtime::obj transient_sorted_set_ref transient_sorted_set::conj_in_place(object_ref const elem) { assert_active(); - data.insert_v(elem); + data.insert(elem); return this; } @@ -72,7 +67,7 @@ namespace jank::runtime::obj { assert_active(); active = false; - return make_box(data.persistent()); + return make_box(data); } object_ref transient_sorted_set::call(object_ref const elem) @@ -81,7 +76,7 @@ namespace jank::runtime::obj auto const found(data.find(elem)); if(found != data.end()) { - return found.get(); + return *found; } return jank_nil; } @@ -92,7 +87,7 @@ namespace jank::runtime::obj auto const found(data.find(elem)); if(found != data.end()) { - return found.get(); + return *found; } return fallback; } @@ -109,11 +104,10 @@ namespace jank::runtime::obj object_ref transient_sorted_set::get_entry(object_ref const elem) { - auto const found = call(elem); - auto const nil(jank_nil); - if(found == nil) + auto const found{ call(elem) }; + if(found == jank_nil) { - return nil; + return found; } return make_box(std::in_place, found, found); @@ -128,7 +122,7 @@ namespace jank::runtime::obj transient_sorted_set_ref transient_sorted_set::disjoin_in_place(object_ref const elem) { assert_active(); - data.erase_key(elem); + data.erase(elem); return this; } diff --git a/compiler+runtime/third-party/bpptree b/compiler+runtime/third-party/bpptree deleted file mode 160000 index addf92b02..000000000 --- a/compiler+runtime/third-party/bpptree +++ /dev/null @@ -1 +0,0 @@ -Subproject commit addf92b029bef74ae07f4ebb7e82312a6950ae8c From c561a8533307ff51d4828ccc529064a0e8207180 Mon Sep 17 00:00:00 2001 From: jeaye Date: Wed, 5 Nov 2025 14:39:31 -0800 Subject: [PATCH 7/7] Remove direct std::set usages --- compiler+runtime/src/cpp/jank/ui/highlight.cpp | 2 +- compiler+runtime/src/cpp/jank/util/try.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler+runtime/src/cpp/jank/ui/highlight.cpp b/compiler+runtime/src/cpp/jank/ui/highlight.cpp index 7c70d3812..b22afcf11 100644 --- a/compiler+runtime/src/cpp/jank/ui/highlight.cpp +++ b/compiler+runtime/src/cpp/jank/ui/highlight.cpp @@ -10,7 +10,7 @@ namespace jank::ui using namespace ftxui; /* TODO: Also support core fns? */ - static std::set const specials{ + static native_set const specials{ "def", "fn*", "fn", "let*", "let", "loop*", "loop", "do", "if", "quote", "var", "try", "catch", "finally", "throw", "letfn*", }; diff --git a/compiler+runtime/src/cpp/jank/util/try.cpp b/compiler+runtime/src/cpp/jank/util/try.cpp index 0a4430917..c50e77d98 100644 --- a/compiler+runtime/src/cpp/jank/util/try.cpp +++ b/compiler+runtime/src/cpp/jank/util/try.cpp @@ -47,7 +47,7 @@ namespace jank::util * at the start/end of each stack trace. */ static bool filter_frame(cpptrace::stacktrace_frame const &frame) { - static std::set const symbols_to_ignore{ + static native_set const symbols_to_ignore{ /* (Top) Linux exception pipework. */ "get_adjusted_ptr", "__gxx_personality_v0",