From cb29d009d3348ff77f62e5a59ff7f93619f2ef49 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Feb 2026 13:17:21 -0500 Subject: [PATCH] xo-expression2: DGlobalSymtab mvp implementation --- .../include/xo/expression2/DGlobalSymtab.hpp | 47 ++++++++-- .../src/expression2/DGlobalSymtab.cpp | 90 +++++++++++++++---- 2 files changed, 112 insertions(+), 25 deletions(-) diff --git a/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp b/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp index 0aca15c6..32fb9570 100644 --- a/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp +++ b/xo-expression2/include/xo/expression2/DGlobalSymtab.hpp @@ -25,18 +25,41 @@ namespace xo { public: using key_type = const DUniqueString *; using value_type = Binding; + using ArenaHashMapConfig = xo::map::ArenaHashMapConfig; using repr_type = xo::map::DArenaHashMap; + using ACollector = xo::mm::ACollector; using AAllocator = xo::mm::AAllocator; using MemorySizeVisitor = xo::mm::MemorySizeVisitor; public: + /** @defgroup scm-globalsymtab-ctors constructors **/ + ///@{ + + DGlobalSymtab(repr_type * map, DArray * vars); + + /** create instance. + * Use memory from @p fixed_mm for @ref map_. + * Use memory from @p mm for DGlobalSymtab instance. + * Hashmap configured per @p cfg. + **/ + DGlobalSymtab * make(obj fixed_mm, + obj mm, + const ArenaHashMapConfig & cfg); + + ///@} + /** @defgroup scm-globalsymtab-access-methods access methods **/ + ///@{ + /** visit symtab-owned memory pools; call visitor(info) for each **/ void visit_pools(const MemorySizeVisitor & visitor) const; - public: /** lookup global symbol with name @p sym **/ DVariable * lookup_variable(const DUniqueString * sym) const noexcept; + ///@} + /** @defgroup scm-globalsymtab-general-methods general methods **/ + ///@{ + /** establish binding for @p sym, with type described by @p typeref, * replacing existing global (if present) with the same name. * Use memory from @p mm to create variable-expr @@ -45,7 +68,8 @@ namespace xo { const DUniqueString * sym, TypeRef typeref); - /** @defgroup xo-expression2-symboltable-facet symboltable facet**/ + ///@} + /** @defgroup scm-globalsymtab-symboltable-facet symboltable facet **/ ///@{ /** true for global symbol table **/ @@ -55,13 +79,22 @@ namespace xo { Binding lookup_binding(const DUniqueString * sym) const noexcept; ///@} + /** @defgroup scm-globalsymtab-gcobject-facet gcobject facet **/ + ///@{ + + std::size_t shallow_size() const noexcept; + DGlobalSymtab * shallow_copy(obj mm) const noexcept; + std::size_t forward_children(obj gc) noexcept; + ///@} + private: - /** next binding will use this global index. See DGlobalEnv **/ - uint32_t next_binding_ix_ = 0; - - /** map symbols -> bindings **/ - repr_type map_; + /** map symbols -> bindings. + * Minor point: storing offsets instead of Variables allows us to omit + * iterating over map elements during GC. Possible savings if map_ slots + * sparsely populated. + **/ + repr_type * map_ = nullptr; /** array of variables. * When S is a unique-string for a global symbol, then: diff --git a/xo-expression2/src/expression2/DGlobalSymtab.cpp b/xo-expression2/src/expression2/DGlobalSymtab.cpp index 10e1665f..85fd6e93 100644 --- a/xo-expression2/src/expression2/DGlobalSymtab.cpp +++ b/xo-expression2/src/expression2/DGlobalSymtab.cpp @@ -7,32 +7,57 @@ #include "DUniqueString.hpp" #include #include +#include #include #include #include namespace xo { + using xo::map::DArenaHashMap; using xo::mm::AGCObject; namespace scm { -#ifdef NOT_YET - DVariable * - DGlobalSymtab::lookup_binding(Binding ix) noexcept + DGlobalSymtab::DGlobalSymtab(repr_type * map, + DArray * vars) + : map_{map}, vars_{vars} { - assert(ix.i_link() == -1); - assert(ix.j_slot() >= 0); - assert(vars_); - assert(std::uint64_t(ix.j_slot()) < vars_->size()); - - auto var_gco = obj::from((*vars_)[ix.j_slot()]);; - auto var = var_gco.to_facet(); - - assert(var.data()); - - return var.data(); } -#endif + + DGlobalSymtab * + DGlobalSymtab::make(obj global_mm, + obj mm, + const ArenaHashMapConfig & cfg) + { + repr_type * map = nullptr; + { + /** memory DGlobalSymtab::map_ + * (but not counting the mmap()'s that map will make for itself) + **/ + void * global_mem = global_mm.alloc_for(); + + map = new (global_mem) repr_type(cfg); + } + assert(map); + + void * symtab_mem = mm.alloc_for(); + + /* choosing same capacity for hash, vars */ + DArray * vars = DArray::empty(mm, map->capacity()); + assert(vars); + + DGlobalSymtab * symtab = new (symtab_mem) DGlobalSymtab(map, vars); + assert(symtab); + + return symtab; + } + + void + DGlobalSymtab::visit_pools(const MemorySizeVisitor & visitor) const + { + if (map_) + map_->visit_pools(visitor); + } DVariable * DGlobalSymtab::lookup_variable(const DUniqueString * sym) const noexcept @@ -62,6 +87,9 @@ namespace xo { DArray::size_type n = vars_->size(); + // NOTE: expansion here is moot at present (Feb 2026). + // Not implemented in ArenaHashMap + /** make sure vars_ has room **/ if (n == vars_->capacity()) { // reallocate with more capacity @@ -82,7 +110,9 @@ namespace xo { return var; } - map_[sym] = binding.j_slot(); + assert(map_->size() < map_->capacity()); + + (*map_)[sym] = binding.j_slot(); bool ok = vars_->push_back(obj(var)); @@ -101,14 +131,38 @@ namespace xo { scope log(XO_DEBUG(true), "stub"); log && log(xtag("sym", std::string_view(*sym))); - auto ix = map_.find(sym); + auto ix = map_->find(sym); - if (ix == map_.end()) + if (ix == map_->end()) return Binding::null(); return Binding::global(ix->second); } + // ----- gcobject facet ----- + + std::size_t + DGlobalSymtab::shallow_size() const noexcept + { + return sizeof(DGlobalSymtab); + } + + DGlobalSymtab * + DGlobalSymtab::shallow_copy(obj mm) const noexcept + { + return mm.std_copy_for(this); + } + + std::size_t + DGlobalSymtab::forward_children(obj gc) noexcept + { + // map_ doesn't contain any gc-owned data, can skip + + gc.forward_inplace(&vars_); + + return this->shallow_size(); + } + } /*namespace scm*/ } /*namespace xo*/