Stage K-2: COLD forgets to the fence; PAD moved below the block window (FABRIC-3.10.8 §4.2)
- Defect 1: COLD now forgets every word since the fence exactly as FORGET does (new vm_dictionary_forget_to_fence(): untrack, metrics, entry) and rewinds HERE to the fence. It rewound HERE alone to 1024, leaving live words to be compiled over. - Defect 2: PAD = BLK_VM_WINDOW_BASE - 512 (was inside the window's top slot, shared with BLOCK/BUFFER). - Probe (plain FORTH, all three ISAs identical): PAD..PAD+511 = 5238272..5238783 below the window (5238784); on a worker KA/KC found, COLD, then KA/KB/KC not found, HERE at the fence (1424), new word works. - Standard sequence on amd64/aarch64/riscv64: hash and G unchanged, MINT/WIREBIND/USE ok, conserved, 0 idle growth. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
27c430e0ca
commit
c9c97cf769
@@ -692,3 +692,33 @@ void vm_unpin_execution_heat(VM *vm) {
|
||||
|
||||
/* MC-0c: vm_dictionary_index_reset() (the global index's hard reset, no
|
||||
* callers) is gone; a VM's index is freed with the VM, vm_dictionary_index_free(). */
|
||||
|
||||
/* FABRIC-3.10.8 K-2: forget everything defined since the fence, exactly as
|
||||
* FORGET removes words (untrack -- id recycled, Stadium cell reclaimed --
|
||||
* then metrics, then the entry), and rewind HERE to the fence. COLD's
|
||||
* dictionary half: it used to rewind HERE alone, leaving `latest` pointing
|
||||
* at words whose code HERE would then compile over. Returns the number of
|
||||
* words forgotten. */
|
||||
int vm_dictionary_forget_to_fence(VM *vm) {
|
||||
int n = 0;
|
||||
DictEntry *e;
|
||||
if (!vm) return 0;
|
||||
sf_mutex_lock(&vm->dict_lock);
|
||||
e = vm->latest;
|
||||
while (e && e != vm->dict_fence_latest) {
|
||||
DictEntry *next = e->link;
|
||||
vm_dictionary_untrack_entry(vm, e);
|
||||
if (e->transition_metrics) {
|
||||
transition_metrics_cleanup(e->transition_metrics);
|
||||
sf_free(e->transition_metrics);
|
||||
e->transition_metrics = NULL;
|
||||
}
|
||||
sf_free(e);
|
||||
n++;
|
||||
e = next;
|
||||
}
|
||||
vm->latest = vm->dict_fence_latest;
|
||||
vm->here = vm->dict_fence_here;
|
||||
sf_mutex_unlock(&vm->dict_lock);
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -161,10 +161,14 @@ void dictionary_word_2comma(VM *vm) {
|
||||
/**
|
||||
* @brief PAD ( -- addr ) Get scratch pad buffer address
|
||||
* @param vm Pointer to the VM structure
|
||||
* @details Returns VM address of 512-byte temporary text buffer at top of memory
|
||||
* @details Returns VM address of the 512-byte temporary text buffer: the
|
||||
* 512 bytes just below the block I/O window. FABRIC-3.10.8 K-2: it used to
|
||||
* be VM_MEMORY_SIZE - 512, inside the window's top slot, so BLOCK/BUFFER
|
||||
* and PAD overwrote each other. The span between the dictionary limit
|
||||
* (DICTIONARY_MEMORY_SIZE) and the window is otherwise unused.
|
||||
*/
|
||||
void dictionary_word_pad(VM *vm) {
|
||||
size_t pad_offset = VM_MEMORY_SIZE - 512;
|
||||
size_t pad_offset = BLK_VM_WINDOW_BASE - 512;
|
||||
vm_push(vm, (cell_t) pad_offset);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,18 +88,14 @@ static void reset_vm_state(VM *vm, int cold_start) {
|
||||
vm->mode = MODE_INTERPRET;
|
||||
|
||||
if (cold_start) {
|
||||
/* In a complete system, this would restore a boot image.
|
||||
For now we keep a minimal fence by not crushing the base dictionary. */
|
||||
if (vm->here > 1024) {
|
||||
/* S-1c: never below the input buffers allotted at vm_init()
|
||||
* (TIB/>IN/SPAN/WORD buffer end past 1024). */
|
||||
size_t floor = 1024;
|
||||
if (vm->word_buf) {
|
||||
size_t buf_end = (size_t)(vm->word_buf - vm->memory) + WORD_BUFFER_SIZE;
|
||||
if (buf_end > floor) floor = buf_end;
|
||||
}
|
||||
if (vm->here > floor) vm->here = floor;
|
||||
}
|
||||
/* FABRIC-3.10.8 K-2: back to the post-boot dictionary -- every word
|
||||
* defined since the fence forgotten (as FORGET does it) and HERE at
|
||||
* the fence. This used to rewind HERE alone, to 1024, leaving
|
||||
* `latest` pointing at live words that the next definitions then
|
||||
* compiled over. The fence is set after vm_init() allots the input
|
||||
* buffers (S-1c), so HERE never lands below them. */
|
||||
int n = vm_dictionary_forget_to_fence(vm);
|
||||
log_message(LOG_INFO, "COLD: %d word(s) forgotten, HERE=%ld", n, (long) vm->here);
|
||||
}
|
||||
|
||||
system_running = 1;
|
||||
|
||||
Reference in New Issue
Block a user