Download Game! Currently 54 players and visitors. Last logged in:FloppyDeinoArnoldiDeathwish

Blitzer's Blog >> 72233

Back to blogs index
Posted: 10 Sep 2026 07:55 [ permalink ]
console.log("Result:", finalResult);

-UUU:---  F1  mvp.js         Bot   L306   (JavaScript) 
[1]+  Stopped                    emacs mvp.js
user@elli:~/Downloads/Remote/AST$ node mvp.js
Result: 30
user@elli:~/Downloads/Remote/AST$

==

Excellent. Result: 30 is exactly the correct output!
Your let block correctly evaluated the auth_check module (which assigned
"AUTHORIZED" to result), and then the block evaluated its final bodythe
client's payload ["+", 10, 20]which successfully returned 30.
You now have a fully functioning, lexer-free, memory-safe, composable virtual
machine.
Now we move to Phase 5: Async and Parallel Execution.
To achieve deterministic execution bounds where the main thread can "demand"
the current state of a task without blocking Node's event loop, we must
implement the lock-free Sequence Lock (SeqLock) pattern using
SharedArrayBuffer and Atomics.
Here is the exact architecture to add to your MVP.
1. The Lock-Free State Buffer
We will create a 12-byte buffer.
Index 0: The Sequence number (odd means writing, even means stable).
Index 1: The Status (0 = Init, 1 = Running, 2 = Complete, 3 = Cancelled).
Index 2: The Payload (For the MVP, an intermediate or final integer result).
Add this class to your architecture:
/ A lock-free channel between the Main Thread and the Worker
class StateBuffer {
  constructor(sab = new SharedArrayBuffer(12)) {
    this.int32 = new Int32Array(sab);
  }

  // PRODUCER (Worker Thread)
  writeState(status, value) {
    // 1. Increment sequence to an ODD number (locks the readers)
    Atomics.add(this.int32, 0, 1); 
    
    // 2. Write the actual data
    Atomics.store(this.int32, 1, status);
    if (value !== undefined) {
      Atomics.store(this.int32, 2, value);
    }
    
    // 3. Increment sequence to an EVEN number (unlocks the readers)
    Atomics.add(this.int32, 0, 1); 
  }

  // CONSUMER (Main Thread)
  readState() {
    let seq1, seq2, status, value;
    do {
      // 1. Read the initial sequence
      seq1 = Atomics.load(this.int32, 0);
      
      // If odd, a write is in progress. Spin loop (continue).
      if (seq1 % 2 !== 0) continue; 
      
      // 2. Read the data
      status = Atomics.load(this.int32, 1);
      value = Atomics.load(this.int32, 2);
      
      // 3. Read the sequence again to ensure it didn't change while reading
      seq2 = Atomics.load(this.int32, 0);
      
    } while (seq1 !== seq2);

    return { status, value };
  }
}

2. Modifying the VM for Bounded Execution (Worker Side)
Inside the worker thread, the VM loop is modified to accept a gasLimit (a
maximum instruction count) and the StateBuffer. It periodically publishes its
current state to the buffer.
function executeVMWorker(mainBytecode, stateBuffer, gasLimit) {
  // ...j
}

3. The Main Thread Polling Loop
Because the buffer is lock-free, the main Node.js event loop can synchronously
inspect the state of the worker at any time, enforce a wall-clock deadline,
and return a partial result if necessary.
const { Worker, isMainThread, workerData } = require('worker_threads');

if (isMainThread) {
  // 1. Set up the memory and buffer
  const sab = new SharedArrayBuffer(12);
  const stateBuffer = new StateBuffer(sab);
  
  // 2. We compile a computationally heavy payload
  const heavyPayload = ["let", [["i", 0]], /* ... large loop AST ... */];
  const bytecode = compile(heavyPayload);

  // 3. Spawn the worker (passing the SAB and the bytecode)
  const worker = new Worker(__filename, { 
    workerData: { bytecode, sab, gasLimit: 500 } 
  });

  // 4. Enforce Wall-Clock Determinism
  const DEADLINE_MS = 10; 
  const startTime = Date.now();

  const pollInterval = setInterval(() => {
    const currentState = stateBuffer.readState();
    console.log(`Polling... Status: ${currentState.status}, Val:
${currentState.value}`);

    // If time is up, or the task finished naturally
    if (Date.now() - startTime >= DEADLINE_MS || currentState.status >= 2) {
      clearInterval(pollInterval);
      worker.terminate(); // Safely kill the thread
      console.log(`Execution ended. Final captured state:`, currentState);
    }
  }, 2); // Poll every 2ms
  
} else {
  // --- WORKER THREAD LOGIC ---
  const stateBuffer = new StateBuffer(workerData.sab);
  executeVMWorker(workerData.bytecode, stateBuffer, workerData.gasLimit);
}

Why this is production-grade
This completely isolates user-submitted ASTs from your edge gateway.
If the user submits an infinite loop (while(true) equivalent), the gasLimit
stops it logically.
If the operations themselves are unexpectedly heavy, the DEADLINE_MS
wall-clock polling kills the worker thread and safely returns the last known
good state from the ring buffer.
Your API gateway never hangs.