Files

202 lines
6.0 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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*: Cant 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