Download Game! Currently 110 players and visitors. Last logged in:TatzaSirdaWarundVenturus

Blitzer's Blog >> 71855

Back to blogs index
Posted: 29 Aug 2026 23:05 [ permalink ]
These terminal logs are glorious to see. Seeing the Data Arena correctly
report 22 bytes ("Hello " = 6 bytes, "HAUKI" = 5 bytes, "Hello HAUKI" = 11
bytes) and the Master Object Index (MOI) safely routing state offsets means
the fundamental memory architecture is 100% proven.
You have successfully constructed the memory isolation layer required for Ring
0.
Now, we must transform this single-threaded, synchronous calculator into a
Cooperative Multi-Tasking Microkernel.
Here is the architectural specification for Phase 3: The Execution Context
(CTX), Scheduler, and Formal ABI.
1. The Execution Context (CTX) Memory Layout
Currently, your ip, sp, registers, and shadowStack are properties attached
directly to the VM class. To support hundreds of concurrent LPC objects
running at once, this state must be decoupled.
In a C/x86 kernel, a Green Thread (Coroutine) is just a contiguous block of
memory. We will define the CTX as a flat memory struct.
For the JS MVP, this can be represented as a single Int32Array of 1040 slots
(4,160 bytes) per active thread.
| Offset / Index | Type (32-bit) | Field Name | Description |
|---|---|---|---|
| 0 | int32 | oid | The Master Object Index (MOI) ID this thread belongs to. |
| 1 | int32 | ip | The current Instruction Pointer. |
| 2 | int32 | sp | The current Shadow Stack Pointer. |
| 3 | int32 | gas | Remaining execution ticks before yielding. |
| 4 | int32 | status | 0 = RUNNABLE, 1 = WAITING_IO, 2 = DEAD. |
| 5 to 12 | int32 | R0 - R7 | The 8 Virtual CPU Registers. |
| 16 to 1039 | int32 | ShadowStack | The 1024-slot private stack for this
thread. |
2. The Formal ABI & Shadow Stack
When one function calls another, we must strictly define which registers
survive the call. We use a standard C-style ABI.
 * R0 (Accumulator): Volatile. Used to return values.
 * R1, R2 (Arguments): Volatile. Used to pass arguments to functions and
Syscalls.
 * R3 through R7 (Locals): Preserved. Used for local variables.
The CALL_ABS Protocol (Pushing a Frame):
When a CALL occurs, the engine pushes exactly 6 integers to the Shadow Stack:
 * Push IP (Return Address).
 * Push R3, R4, R5, R6, R7. (We do not save R0, R1, or R2, as the caller knows
they will be destroyed).
The RETURN Protocol (Popping a Frame):
 * Pop R7 down through R3.
 * Pop IP.
 * Note: R0 remains exactly what the subroutine left it as, allowing it to act
as the return value.
3. The Tag-Aware ALU (Arithmetic Logic Unit)
Before we can run real LPC logic, we need math. But because our registers hold
Tagged Pointers, an ADD instruction cannot just blindly add R1 and R2.
If R1 holds (5 << 3) | 1 (Tagged Integer 5) and R2 holds (10 << 3) | 1 (Tagged
Integer 10), the VM must validate the tags before executing the math.
Specification for 0x21: ADD DEST, SRC
 * Read registers[DEST] and registers[SRC].
 * Extract the lowest 3 bits of both.
 * Type Check: If both are not TAG_INT (1), throw a safe VM exception (e.g.,
"Type mismatch in addition").
 * Untag: Shift both right by 3 (>>> 3).
 * Execute: Add the raw integers.
 * Retag: Shift the result left by 3 and bitwise OR with TAG_INT ((result <<
3) | 1).
 * Store in registers[DEST].
Note: In the eventual x86 JIT, we will use the hardware trick discussed
previously to do this without untagging, but for the JS interpreter, explicit
untag-math-retag is the safest and most readable approach.
4. The Microkernel Scheduler Loop
The VM's run() loop must be rewritten. It is no longer executing a single
script until it finishes. It is now pulling threads from a Run Queue.
The Scheduler Algorithm:
 * Pop the next CTX from the runQueue.
 * Load the CTX state (ip, sp, registers) into the VM's active CPU variables
(for fast memory access).
 * Execute instructions. For every backward jump or CALL, decrement gas.
 * If gas <= 0:
   * Flush the active CPU variables back into the CTX array.
   * Push the CTX to the back of the runQueue.
   * Break the inner execution loop to yield to the next thread.
 * If RETURN hits an empty stack (Thread is finished):
   * Set status = DEAD.
   * Do not push it back to the queue.
The Goal for Your Next Dev-Session
In your dev-environment, your objective is to refactor the MVP execution
engine into this Microkernel architecture.
Write a JS test script that proves concurrency:
 * Define the CTX layout as an Int32Array.
 * Refactor the VM to use a runQueue.
 * Create two separate CTX threads.
   * Thread A: A loop that counts from 10 down to 0, using the new ADD/SUB ALU
instructions.
   * Thread B: A loop that counts from 5 down to 0.
 * Set the gas limit incredibly low (e.g., 3 instructions per timeslice).
 * Execute the Scheduler.
Expected Output: You should see the VM perfectly interleave the execution of
Thread A and Thread B, yielding back and forth, printing output, without the
state of R1 in Thread A ever corrupting the state of R1 in Thread B.