xo-expression2: DGlobalSymtab mvp implementation

This commit is contained in:
Roland Conybeare 2026-02-15 13:17:21 -05:00
commit b187f1a719
2 changed files with 109 additions and 22 deletions

View file

@ -25,18 +25,41 @@ namespace xo {
public: public:
using key_type = const DUniqueString *; using key_type = const DUniqueString *;
using value_type = Binding; using value_type = Binding;
using ArenaHashMapConfig = xo::map::ArenaHashMapConfig;
using repr_type = xo::map::DArenaHashMap<key_type, Binding::slot_type>; using repr_type = xo::map::DArenaHashMap<key_type, Binding::slot_type>;
using ACollector = xo::mm::ACollector;
using AAllocator = xo::mm::AAllocator; using AAllocator = xo::mm::AAllocator;
using MemorySizeVisitor = xo::mm::MemorySizeVisitor; using MemorySizeVisitor = xo::mm::MemorySizeVisitor;
public: 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<AAllocator> fixed_mm,
obj<AAllocator> mm,
const ArenaHashMapConfig & cfg);
///@}
/** @defgroup scm-globalsymtab-access-methods access methods **/
///@{
/** visit symtab-owned memory pools; call visitor(info) for each **/ /** visit symtab-owned memory pools; call visitor(info) for each **/
void visit_pools(const MemorySizeVisitor & visitor) const; void visit_pools(const MemorySizeVisitor & visitor) const;
public:
/** lookup global symbol with name @p sym **/ /** lookup global symbol with name @p sym **/
DVariable * lookup_variable(const DUniqueString * sym) const noexcept; 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, /** establish binding for @p sym, with type described by @p typeref,
* replacing existing global (if present) with the same name. * replacing existing global (if present) with the same name.
* Use memory from @p mm to create variable-expr * Use memory from @p mm to create variable-expr
@ -45,7 +68,8 @@ namespace xo {
const DUniqueString * sym, const DUniqueString * sym,
TypeRef typeref); TypeRef typeref);
/** @defgroup xo-expression2-symboltable-facet symboltable facet**/ ///@}
/** @defgroup scm-globalsymtab-symboltable-facet symboltable facet **/
///@{ ///@{
/** true for global symbol table **/ /** true for global symbol table **/
@ -55,13 +79,22 @@ namespace xo {
Binding lookup_binding(const DUniqueString * sym) const noexcept; 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<AAllocator> mm) const noexcept;
std::size_t forward_children(obj<ACollector> gc) noexcept;
///@}
private: private:
/** next binding will use this global index. See DGlobalEnv **/ /** map symbols -> bindings.
uint32_t next_binding_ix_ = 0; * Minor point: storing offsets instead of Variables allows us to omit
* iterating over map elements during GC. Possible savings if map_ slots
/** map symbols -> bindings **/ * sparsely populated.
repr_type map_; **/
repr_type * map_ = nullptr;
/** array of variables. /** array of variables.
* When S is a unique-string for a global symbol, then: * When S is a unique-string for a global symbol, then:

View file

@ -7,32 +7,57 @@
#include "DUniqueString.hpp" #include "DUniqueString.hpp"
#include <xo/expression2/Expression.hpp> #include <xo/expression2/Expression.hpp>
#include <xo/expression2/Variable.hpp> #include <xo/expression2/Variable.hpp>
#include <xo/object2/Array.hpp>
#include <xo/gc/GCObject.hpp> #include <xo/gc/GCObject.hpp>
#include <xo/facet/FacetRegistry.hpp> #include <xo/facet/FacetRegistry.hpp>
#include <xo/indentlog/scope.hpp> #include <xo/indentlog/scope.hpp>
namespace xo { namespace xo {
using xo::map::DArenaHashMap;
using xo::mm::AGCObject; using xo::mm::AGCObject;
namespace scm { namespace scm {
#ifdef NOT_YET DGlobalSymtab::DGlobalSymtab(repr_type * map,
DVariable * DArray * vars)
DGlobalSymtab::lookup_binding(Binding ix) noexcept : 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<AGCObject,DVariable>::from((*vars_)[ix.j_slot()]);;
auto var = var_gco.to_facet<AExpression>();
assert(var.data());
return var.data();
} }
#endif
DGlobalSymtab *
DGlobalSymtab::make(obj<AAllocator> global_mm,
obj<AAllocator> 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<repr_type>();
map = new (global_mem) repr_type(cfg);
}
assert(map);
void * symtab_mem = mm.alloc_for<DGlobalSymtab>();
/* 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 * DVariable *
DGlobalSymtab::lookup_variable(const DUniqueString * sym) const noexcept DGlobalSymtab::lookup_variable(const DUniqueString * sym) const noexcept
@ -62,6 +87,9 @@ namespace xo {
DArray::size_type n = vars_->size(); DArray::size_type n = vars_->size();
// NOTE: expansion here is moot at present (Feb 2026).
// Not implemented in ArenaHashMap
/** make sure vars_ has room **/ /** make sure vars_ has room **/
if (n == vars_->capacity()) { if (n == vars_->capacity()) {
// reallocate with more capacity // reallocate with more capacity
@ -82,7 +110,9 @@ namespace xo {
return var; return var;
} }
map_[sym] = binding.j_slot(); assert(map_->size() < map_->capacity());
(*map_)[sym] = binding.j_slot();
bool ok = vars_->push_back(obj<AGCObject,DVariable>(var)); bool ok = vars_->push_back(obj<AGCObject,DVariable>(var));
@ -101,14 +131,38 @@ namespace xo {
scope log(XO_DEBUG(true), "stub"); scope log(XO_DEBUG(true), "stub");
log && log(xtag("sym", std::string_view(*sym))); 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::null();
return Binding::global(ix->second); return Binding::global(ix->second);
} }
// ----- gcobject facet -----
std::size_t
DGlobalSymtab::shallow_size() const noexcept
{
return sizeof(DGlobalSymtab);
}
DGlobalSymtab *
DGlobalSymtab::shallow_copy(obj<AAllocator> mm) const noexcept
{
return mm.std_copy_for<DGlobalSymtab>(this);
}
std::size_t
DGlobalSymtab::forward_children(obj<ACollector> gc) noexcept
{
// map_ doesn't contain any gc-owned data, can skip
gc.forward_inplace(&vars_);
return this->shallow_size();
}
} /*namespace scm*/ } /*namespace scm*/
} /*namespace xo*/ } /*namespace xo*/