// Moved from docs/src/platform-integration/L4RE_DICTIONARY_ALLOCATION.adoc to docs/working/scratch/src/platform-integration/L4RE_DICTIONARY_ALLOCATION.adoc on 2026-06-16 (docs reorg Phase 2)
== Dictionary Allocation Strategy for L4Re
:toc: left
:toc-title: Contents
:toclevels: 3
xref:../README.adoc[← Back to Documentation Index]



=== Current Implementation

StarForth currently uses `+malloc()+` and `+free()+` from the host C
library for dictionary entry allocation:

* *Location*: `+src/dictionary_management.c:228+`
* *Function*: `+vm_create_word()+` uses `+malloc(total)+` to allocate
DictEntry structures
* *Cleanup*: `+FORGET+` uses `+free(e)+` to deallocate entries (line 554
in defining_words.c)

This works fine for hosted environments but creates a dependency on libc
heap allocator.

=== Why This Matters for L4Re/StarshipOS

==== Issues with Current Approach:

[arabic]
. *Heap Dependency*: Requires full malloc implementation in L4Re
environment
. *Non-Deterministic*: Heap fragmentation and unpredictable allocation
behavior
. *Separate Address Space*: Dictionary entries live outside VM memory
model
. *Hard to Introspect*: Can’t dump entire VM state as single memory
region

==== Benefits of VM-Based Allocation:

[arabic]
. *Zero External Dependencies*: No libc malloc needed
. *Deterministic*: Simple bump allocator, predictable behavior
. *Unified Address Space*: Everything in one 5MB VM memory region
. *Easy Snapshots*: Can serialize entire VM state
. *Better for Microkernel*: Aligns with L4Re dataspace model

=== Recommended Approach for L4Re

==== Strategy: Conditional Compilation

Add a compile-time flag to switch between malloc and VM-based
allocation:

[source,c]
----
// In dictionary_management.c
#ifdef STARFORTH_VM_DICT_ALLOC
    /* VM-based allocation (for L4Re/embedded) */
    DictEntry *entry = dict_alloc_from_vm(vm, total);
#else
    /* Standard malloc (for hosted environments) */
    DictEntry *entry = (DictEntry *) malloc(total);
#endif
----

==== Memory Layout (VM-Based Mode):

....
vm->memory[0...VM_MEMORY_SIZE] (5MB):
┌──────────────────────────────────────────┐
│ Dictionary Headers (256KB)               │  ← dict_headers_used grows up
│ - DictEntry structures                   │
│ - Allocated via dict_alloc()             │
├──────────────────────────────────────────┤
│ User Data & Code (variable)              │  ← HERE grows up
│ - Compiled definitions                   │
│ - Variables, constants                   │
│ - String literals                        │
├──────────────────────────────────────────┤
│ Block Storage (remainder)                │
│ - 1KB blocks for Forth block system     │
└──────────────────────────────────────────┘
....

==== Implementation Steps:

[arabic]
. *Add Dictionary Allocator* (256KB bump allocator at `+memory[0]+`):

[source,c]
----
static DictEntry *dict_alloc_from_vm(VM *vm, size_t total_bytes) {
    /* Align to cell_t boundary */
    size_t align = sizeof(cell_t);
    total_bytes = (total_bytes + align - 1) & ~(align - 1);

    /* Check space */
    if (vm->dict_headers_used + total_bytes > DICT_HEADERS_MAX) {
        vm->error = 1;
        return NULL;
    }

    /* Allocate from VM memory */
    DictEntry *entry = (DictEntry *)(vm->memory + vm->dict_headers_used);
    vm->dict_headers_used += total_bytes;
    return entry;
}
----

[arabic, start=2]
. *Update FORGET* (no individual frees, just rewind):

[source,c]
----
/* Instead of free(e) loop, rewind allocator */
size_t target_offset = (uint8_t*)target - vm->memory;
vm->dict_headers_used = target_offset;
----

[arabic, start=3]
. *Adjust VM Initialization*:

[source,c]
----
vm->dict_headers_used = 0;     /* Headers start at memory[0] */
vm->here = DICT_HEADERS_MAX;   /* User data starts at 256KB */
----

[arabic, start=4]
. *No Changes to Fast-Lookup Cache*: Cache buckets still use malloc for
the pointer arrays, but entries themselves are in VM memory.

==== Testing Strategy:

[source,bash]
----
# Test with standard malloc (current):
make clean && make test

# Test with VM-based allocation:
make clean
CFLAGS="-DSTARFORTH_VM_DICT_ALLOC" make test

# Test L4Re minimal build:
make clean
CFLAGS="-DSTARFORTH_MINIMAL -DSTARFORTH_VM_DICT_ALLOC" make rpi4-cross
----

=== Current Status

*Decision*: Keep using `+malloc()+` for now, document the abstraction
point clearly.

*Rationale*:

* Current implementation is stable and well-tested
* L4Re port can implement the switch when needed
* Abstraction layer is simple and well-defined
* No performance difference between approaches

*Action Items for L4Re Port*:

[arabic]
. Define `+STARFORTH_VM_DICT_ALLOC+` in L4Re build
. Implement `+dict_alloc_from_vm()+` function
. Update `+FORGET+` to use rewind instead of free loop
. Test with full test suite
. Verify no memory leaks in microkernel environment

=== Minimal Code Changes Needed

The switch to VM-based allocation requires changes to only 3 functions:

[arabic]
. *`+vm_create_word()+`* - Use `+dict_alloc_from_vm()+` instead of
`+malloc()+`
. *`+dictionary_word_forget()+`* - Rewind `+dict_headers_used+` instead
of `+free()+` loop
. *`+vm_init()+`* - Initialize `+dict_headers_used+` and offset `+HERE+`

Add to `+VM+` struct in `+include/vm.h+`:

[source,c]
----
size_t dict_headers_used;  /* Bytes used for dictionary headers (VM mode only) */
----

*Estimated effort*: 4 hours to implement + 2 hours testing = *6 hours
total*

=== References

* Current malloc usage: `+src/dictionary_management.c:228+`
* Current free usage: `+src/word_source/defining_words.c:554+`
* Fast-lookup cache: `+src/dictionary_management.c:43-67+` (unchanged)
* L4Re dataspace docs: `+docs/L4RE_INTEGRATION.md+`

'''''

*Author*: R. A. James *Date*: 2025-10-01 *Status*: Documented,
implementation deferred to L4Re port
