From 0c6c643e07086cc91325ee012cf133cd4b5ba3da Mon Sep 17 00:00:00 2001 From: Oleksandr Kozachuk Date: Tue, 7 Apr 2026 15:11:13 +0200 Subject: [PATCH] Sync HERE to WASM memory, replace HERE host function with Forth (Phase 4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HERE is now defined in boot.fth as `: HERE 12 @ ;` (reads SYSVAR_HERE from WASM linear memory). The Rust side syncs user_here to memory[12]: - At the start of each evaluate() call (sync_here_to_wasm) - In each host function that modifies HERE (ALLOT, comma, C-comma, ALIGN) This avoids per-token sync overhead — only 2 sync points per evaluate() call plus host-function writes. Removed the HERE host function closure (~30 lines). All 426 tests pass. --- crates/core/boot.fth | 11 +++++ crates/core/src/outer.rs | 97 ++++++++++++++++++---------------------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/crates/core/boot.fth b/crates/core/boot.fth index 53f5449..db467e4 100644 --- a/crates/core/boot.fth +++ b/crates/core/boot.fth @@ -137,3 +137,14 @@ \ */MOD ( n1 n2 n3 -- rem quot ) : */MOD >R M* R> FM/MOD ; + +\ --------------------------------------------------------------- +\ Phase 4: HERE and ALIGNED +\ --------------------------------------------------------------- + +\ HERE reads from SYSVAR_HERE (offset 12 in WASM memory). +\ The Rust side syncs user_here to memory[12] before each evaluate call +\ and whenever host ALLOT/comma modifies it. +: HERE 12 @ ; + +\ ALIGNED is already an IR primitive in the compiler. diff --git a/crates/core/src/outer.rs b/crates/core/src/outer.rs index 6dba4c7..f659d19 100644 --- a/crates/core/src/outer.rs +++ b/crates/core/src/outer.rs @@ -22,8 +22,8 @@ use crate::dictionary::{Dictionary, WordId}; use crate::ir::IrOp; use crate::memory::{ CELL_SIZE, DATA_STACK_TOP, FLOAT_SIZE, FLOAT_STACK_BASE, FLOAT_STACK_TOP, INPUT_BUFFER_BASE, - INPUT_BUFFER_SIZE, RETURN_STACK_TOP, SYSVAR_BASE_VAR, SYSVAR_NUM_TIB, SYSVAR_STATE, - SYSVAR_TO_IN, + INPUT_BUFFER_SIZE, RETURN_STACK_TOP, SYSVAR_BASE_VAR, SYSVAR_HERE, SYSVAR_NUM_TIB, + SYSVAR_STATE, SYSVAR_TO_IN, }; use crate::optimizer::optimize; @@ -368,6 +368,7 @@ impl ForthVM { self.input_buffer = input.to_string(); self.input_pos = 0; self.sync_input_to_wasm(); + self.sync_here_to_wasm(); while let Some(token) = self.next_token() { self.sync_input_to_wasm(); @@ -2108,7 +2109,9 @@ impl ForthVM { // (VARIABLE, CONSTANT, CREATE are special tokens) // -- Priority 3: Memory/system words -- - self.register_here()?; + // HERE: defined in boot.fth (reads SYSVAR_HERE from WASM memory). + // Initialize the here_cell for host functions that still need it. + self.here_cell = Some(Arc::new(Mutex::new(self.user_here))); self.register_allot()?; self.register_comma()?; self.register_c_comma()?; @@ -2996,43 +2999,12 @@ impl ForthVM { // Priority 3: Memory/system host functions // ----------------------------------------------------------------------- - /// HERE -- push the current user data pointer. - fn register_here(&mut self) -> anyhow::Result<()> { - let memory = self.memory; - let dsp = self.dsp; - - // Use a shared cell that tracks user_here. - let here_cell = Arc::new(Mutex::new(self.user_here)); - self.here_cell = Some(Arc::clone(&here_cell)); - - let func = Func::new( - &mut self.store, - FuncType::new(&self.engine, [], []), - move |mut caller, _params, _results| { - let here_val = *here_cell.lock().unwrap(); - let sp = dsp.get(&mut caller).unwrap_i32() as u32; - let mem_len = memory.data(&caller).len() as u32; - if sp < CELL_SIZE || sp > mem_len { - return Err(wasmtime::Error::msg("data stack overflow in HERE")); - } - let new_sp = sp - CELL_SIZE; - let data = memory.data_mut(&mut caller); - let bytes = (here_val as i32).to_le_bytes(); - data[new_sp as usize..new_sp as usize + 4].copy_from_slice(&bytes); - dsp.set(&mut caller, Val::I32(new_sp as i32))?; - Ok(()) - }, - ); - - self.register_host_primitive("HERE", false, func)?; - Ok(()) - } - - /// Keep the `here_cell` in sync with `user_here`. - fn sync_here_cell(&self) { + /// Keep the `here_cell` and WASM `memory[SYSVAR_HERE]` in sync with `user_here`. + fn sync_here_cell(&mut self) { if let Some(ref cell) = self.here_cell { *cell.lock().unwrap() = self.user_here; } + self.sync_here_to_wasm(); } /// Sync a new `word_pfa_map` entry to the shared copy (for >BODY host function). @@ -3049,6 +3021,15 @@ impl ForthVM { } } + /// Write `user_here` to WASM `memory[SYSVAR_HERE]` so Forth code can read it. + /// Refreshes from `here_cell` first in case a host function updated it. + fn sync_here_to_wasm(&mut self) { + self.refresh_user_here(); + let data = self.memory.data_mut(&mut self.store); + data[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] + .copy_from_slice(&self.user_here.to_le_bytes()); + } + /// ALLOT -- ( n -- ) advance HERE by n bytes. fn register_allot(&mut self) -> anyhow::Result<()> { let memory = self.memory; @@ -3069,6 +3050,10 @@ impl ForthVM { if let Some(ref cell) = here_cell { let mut h = cell.lock().unwrap(); *h = (*h as i32 + n) as u32; + let new_here = *h; + let data = memory.data_mut(&mut caller); + data[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] + .copy_from_slice(&new_here.to_le_bytes()); } Ok(()) }, @@ -3098,10 +3083,12 @@ impl ForthVM { if let Some(ref cell) = here_cell { let mut h = cell.lock().unwrap(); let addr = *h as usize; - let data = memory.data_mut(&mut caller); - let bytes = value.to_le_bytes(); - data[addr..addr + 4].copy_from_slice(&bytes); *h += CELL_SIZE; + let new_here = *h; + let data = memory.data_mut(&mut caller); + data[addr..addr + 4].copy_from_slice(&value.to_le_bytes()); + data[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] + .copy_from_slice(&new_here.to_le_bytes()); } Ok(()) }, @@ -3129,9 +3116,12 @@ impl ForthVM { if let Some(ref cell) = here_cell { let mut h = cell.lock().unwrap(); let addr = *h as usize; + *h += 1; + let new_here = *h; let data = memory.data_mut(&mut caller); data[addr] = value; - *h += 1; + data[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] + .copy_from_slice(&new_here.to_le_bytes()); } Ok(()) }, @@ -3143,15 +3133,20 @@ impl ForthVM { /// ALIGN -- align HERE to cell boundary. fn register_align(&mut self) -> anyhow::Result<()> { + let memory = self.memory; let here_cell = self.here_cell.clone(); let func = Func::new( &mut self.store, FuncType::new(&self.engine, [], []), - move |_caller, _params, _results| { + move |mut caller, _params, _results| { if let Some(ref cell) = here_cell { let mut h = cell.lock().unwrap(); *h = (*h + 3) & !3; + let new_here = *h; + let data = memory.data_mut(&mut caller); + data[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] + .copy_from_slice(&new_here.to_le_bytes()); } Ok(()) }, @@ -6153,8 +6148,7 @@ impl ForthVM { *cell.lock().unwrap() } else { let mem = memory.data(&caller); - let b: [u8; 4] = mem[crate::memory::SYSVAR_HERE as usize - ..crate::memory::SYSVAR_HERE as usize + 4] + let b: [u8; 4] = mem[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] .try_into() .unwrap(); u32::from_le_bytes(b) @@ -6164,8 +6158,7 @@ impl ForthVM { *cell.lock().unwrap() = aligned; } let mem = memory.data_mut(&mut caller); - mem[crate::memory::SYSVAR_HERE as usize - ..crate::memory::SYSVAR_HERE as usize + 4] + mem[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] .copy_from_slice(&aligned.to_le_bytes()); Ok(()) }, @@ -6772,8 +6765,7 @@ impl ForthVM { *cell.lock().unwrap() } else { let mem = memory.data(&caller); - let b: [u8; 4] = mem[crate::memory::SYSVAR_HERE as usize - ..crate::memory::SYSVAR_HERE as usize + 4] + let b: [u8; 4] = mem[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] .try_into() .unwrap(); u32::from_le_bytes(b) @@ -6783,8 +6775,7 @@ impl ForthVM { *cell.lock().unwrap() = aligned; } let mem = memory.data_mut(&mut caller); - mem[crate::memory::SYSVAR_HERE as usize - ..crate::memory::SYSVAR_HERE as usize + 4] + mem[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] .copy_from_slice(&aligned.to_le_bytes()); Ok(()) }, @@ -6803,8 +6794,7 @@ impl ForthVM { *cell.lock().unwrap() } else { let mem = memory.data(&caller); - let b: [u8; 4] = mem[crate::memory::SYSVAR_HERE as usize - ..crate::memory::SYSVAR_HERE as usize + 4] + let b: [u8; 4] = mem[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] .try_into() .unwrap(); u32::from_le_bytes(b) @@ -6814,8 +6804,7 @@ impl ForthVM { *cell.lock().unwrap() = aligned; } let mem = memory.data_mut(&mut caller); - mem[crate::memory::SYSVAR_HERE as usize - ..crate::memory::SYSVAR_HERE as usize + 4] + mem[SYSVAR_HERE as usize..SYSVAR_HERE as usize + 4] .copy_from_slice(&aligned.to_le_bytes()); Ok(()) },