Move vocabulary and control-flow state off file-scope statics onto VM
proof/FINDINGS.md's Isabelle/HOL word-source sweep (§1) found the two defects severe enough to actively corrupt the live Tripod multi-VM fleet: file-scope C statics standing in for state that belongs on struct VM. - vocabulary_words.c (highest severity in the sweep): forth_vocab/ context_vocab/current_vocab, context_var_addr/current_var_addr, the ctx_fc/forth_fc first-char search index, and the `initialized` guard were all process-wide statics. Only the first VM to touch any vocabulary word ever ran setup; every VM after that silently shared VM #1's dictionary-chain pointers and reused VM #1's byte-offset addresses as if valid in its own vm->memory. One VM's VOCABULARY/ DEFINITIONS/FORTH silently changed where every other VM looked up and defined words. - control_words.c: cf_stack/cf_sp/cf_last_mode (IF/THEN/BEGIN/DO/CASE compile-time nesting) and the LEAVE/ENDOF patch-site bookkeeping (leave_addrs/leave_sp/leave_mark_*, endof_addrs/endof_sp/endof_mark_*) were also process-wide statics. Two VMs compiling colon definitions at overlapping times would corrupt each other's nesting state. Both moved onto struct VM, following the existing hold_addr/hold_pos precedent in include/vm.h ("lives in each VM's own memory... so child VMs never alias Hera's buffer"): - New VocabularyState struct (vm->vocab): chain heads, VM-cell addresses, first-char index, initialized flag. - New ControlFlowState struct (vm->cf): cf_stack/cf_sp/cf_last_mode plus the LEAVE/ENDOF patch-site stacks. cf_tag_t/cf_item_t/CF_STACK_MAX moved from control_words.c into include/vm.h since they're now part of the struct VM field's type. - Sentinel fields (-1/-999, meaning "empty") explicitly initialized in both vm_init_with_host() implementations (hosted src/vm_bootstrap.c and kernel src/starkernel/vm/vm_bootstrap.c) alongside the existing dsp/rsp = -1 initialization, since the preceding zero-init leaves them at 0 rather than their empty sentinel. Every word function in both files already took VM *vm, so no call sites outside these two files needed to change; cf_push_item/cf_pop_item/ cf_peek_item gained a VM* parameter to reach vm->cf. Verified: hosted (amd64) and kernel (amd64, __STARKERNEL__) both build clean with -Wall -Werror after a full clean rebuild (struct VM's layout changed size, and this Makefile has no header-dependency tracking, so a stale incremental build would have linked mismatched object layouts). Hosted POST suite 1012/1012 passing (0 regressions). Manually exercised VOCABULARY/DEFINITIONS/FORTH/ORDER, and IF/ELSE, DO/LOOP/LEAVE, BEGIN/WHILE/REPEAT, and CASE/OF/ENDOF/ENDCASE (including nested DO with I/J) in the REPL -- all correct and unchanged from pre-refactor behavior. Note: a pre-existing CASE/ENDCASE default-clause bug (the code after the last OF...ENDOF pair does not correctly become the "default" value once DROP runs) was found while testing this refactor and confirmed present on unmodified master too -- not touched here, out of scope for this pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014Qf6YcnHgaEtEygq3knx19
This commit is contained in:
@@ -364,6 +364,81 @@ typedef enum
|
||||
MODE_COMPILE = 1
|
||||
} vm_mode_t;
|
||||
|
||||
/* Per-VM vocabulary (VOCABULARY/DEFINITIONS/CONTEXT/CURRENT/FORTH) state.
|
||||
* Was a set of file-scope statics in vocabulary_words.c, shared by every VM
|
||||
* in the process -- one VM's VOCABULARY/DEFINITIONS/FORTH silently changed
|
||||
* where every other VM looked up and defined words (proof/FINDINGS.md #1,
|
||||
* item #5, "highest severity in the sweep"). Moved onto struct VM so each
|
||||
* VM in the fleet keeps its own vocabulary chains, search order, and VM-cell
|
||||
* addresses -- same shape as hold_addr/hold_pos below. */
|
||||
#define VOCAB_FC_BUCKETS 256
|
||||
typedef struct {
|
||||
int initialized;
|
||||
|
||||
/* Host-side vocabulary chain heads */
|
||||
DictEntry *forth_vocab; /* FORTH vocabulary head (root of system) */
|
||||
DictEntry *context_vocab; /* CONTEXT vocabulary head */
|
||||
DictEntry *current_vocab; /* CURRENT vocabulary head */
|
||||
|
||||
/* VM-visible variables: cell addresses in this VM's own memory */
|
||||
vaddr_t context_var_addr; /* cell containing (DictEntry*) CONTEXT */
|
||||
vaddr_t current_var_addr; /* cell containing (DictEntry*) CURRENT */
|
||||
|
||||
/* First-character search index per chain, lazily rebuilt when that
|
||||
* chain's head changes (see vocab_find_word in vocabulary_words.c) */
|
||||
DictEntry **ctx_fc[VOCAB_FC_BUCKETS];
|
||||
size_t ctx_n[VOCAB_FC_BUCKETS];
|
||||
DictEntry *ctx_cached_head;
|
||||
|
||||
DictEntry **forth_fc[VOCAB_FC_BUCKETS];
|
||||
size_t forth_n[VOCAB_FC_BUCKETS];
|
||||
DictEntry *forth_cached_head;
|
||||
} VocabularyState;
|
||||
|
||||
/* Compile-time control-flow bookkeeping for IF/ELSE/THEN, BEGIN/WHILE/REPEAT/
|
||||
* UNTIL/AGAIN, DO/?DO/LOOP/+LOOP/LEAVE, and CASE/OF/ENDOF/ENDCASE.
|
||||
* Was a set of file-scope statics in control_words.c, shared by every VM in
|
||||
* the process -- two VMs compiling control structures at overlapping times
|
||||
* would corrupt each other's nesting state (proof/FINDINGS.md #1, item #1,
|
||||
* "the two that would actually corrupt VM behavior in the live Tripod fleet
|
||||
* today"). Moved onto struct VM so each VM keeps its own compile-time stacks. */
|
||||
#define CF_STACK_MAX 64
|
||||
|
||||
typedef enum {
|
||||
CF_BEGIN, /* Address of BEGIN target */
|
||||
CF_IF, /* Address of IF's 0BRANCH literal */
|
||||
CF_ELSE, /* Address of ELSE's BRANCH literal */
|
||||
CF_WHILE, /* Address of WHILE's 0BRANCH literal (paired with prior BEGIN) */
|
||||
CF_DO, /* Address of loop body start (back target for LOOP/+LOOP) */
|
||||
CF_CASE, /* Marker for CASE statement start */
|
||||
CF_OF /* Address of OF's 0BRANCH literal */
|
||||
} cf_tag_t;
|
||||
|
||||
typedef struct {
|
||||
size_t addr; /* byte offset in vm->memory used for patching/back edges */
|
||||
cf_tag_t tag;
|
||||
} cf_item_t;
|
||||
|
||||
typedef struct {
|
||||
cf_item_t cf_stack[CF_STACK_MAX];
|
||||
int cf_sp;
|
||||
int cf_last_mode; /* reset cf_stack on mode transitions (INTERPRET/COMPILE) */
|
||||
|
||||
/* LEAVE patch sites: one entry per LEAVE, collected until LOOP/+LOOP */
|
||||
size_t leave_addrs[CF_STACK_MAX];
|
||||
int leave_sp;
|
||||
/* One mark per DO nesting: leave_sp at DO/?DO entry, restored at LOOP/+LOOP */
|
||||
int leave_mark_stack[CF_STACK_MAX];
|
||||
int leave_mark_sp;
|
||||
|
||||
/* ENDOF patch sites: one entry per ENDOF, collected until ENDCASE */
|
||||
size_t endof_addrs[CF_STACK_MAX];
|
||||
int endof_sp;
|
||||
/* One mark per CASE nesting: endof_sp at CASE entry, restored at ENDCASE */
|
||||
int endof_mark_stack[CF_STACK_MAX];
|
||||
int endof_mark_sp;
|
||||
} ControlFlowState;
|
||||
|
||||
#ifdef __STARKERNEL__
|
||||
#include "starkernel/vm_uuid.h" /* VMUuid -- item 4.2, VM.stadium_vm_id */
|
||||
#include "starkernel/vm_identity.h" /* VMIdentity -- FABRIC-2.md §F.2/§F.16 */
|
||||
@@ -472,6 +547,9 @@ typedef struct VM
|
||||
vaddr_t hold_addr; /* VM memory offset of the 64-byte pictured-number hold buffer */
|
||||
int hold_pos; /* Current fill count in hold buffer (<# ... #> state) */
|
||||
|
||||
VocabularyState vocab; /* Per-VM VOCABULARY/DEFINITIONS/CONTEXT/CURRENT state */
|
||||
ControlFlowState cf; /* Per-VM compile-time control-flow bookkeeping */
|
||||
|
||||
/* Block I/O window — BLK_VM_SLOTS slots at BLK_VM_WINDOW_BASE in vm->memory.
|
||||
* BLOCK/BUFFER copy C-layer buffers here; UPDATE copies back; lbn==0 means empty. */
|
||||
uint32_t blk_vm_lbn[BLK_VM_SLOTS]; /* LBN currently in each slot (0 = empty) */
|
||||
|
||||
Reference in New Issue
Block a user