Download src/runtime/machine/vm_executor.py from Snapkitty/sovereign-engine-v2: direct link, hf CLI and curl.
- Browser
- Download file 56.2 kB
-
https://huggingface.co/Snapkitty/sovereign-engine-v2/resolve/main/src/runtime/machine/vm_executor.py
- Command line
-
hf download hf://Snapkitty/sovereign-engine-v2/src/runtime/machine/vm_executor.py
-
curl -L -o vm_executor.py https://huggingface.co/Snapkitty/sovereign-engine-v2/resolve/main/src/runtime/machine/vm_executor.py
56.2 kB
| """ | |
| vm_executor.py — Minimal stack-based virtual machine for Sovereign IR. | |
| Executes sovereign IR instructions (VMInstruction objects) on a stack machine. | |
| Enforces the DSL entropy constraint (H <= 0.20) at runtime. | |
| Includes NAND-complete Boolean kernel, routing dispatch, and WORM commit hooks. | |
| Part of the SOVEREIGN_IR PYTHON_C_BRIDGE_IR pipeline. | |
| Agent A (Cognition) — HyperKittyConstraintDSL v1.0 | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| import io | |
| import math | |
| import struct | |
| import time | |
| from dataclasses import dataclass, field | |
| from enum import IntEnum | |
| from typing import Any, Callable, Optional | |
| # --------------------------------------------------------------------------- | |
| # Opcode definitions | |
| # --------------------------------------------------------------------------- | |
| class VMOpcode(IntEnum): | |
| # Stack primitives | |
| NOP = 0x00 | |
| PUSH = 0x01 | |
| POP = 0x02 | |
| DUP = 0x03 | |
| SWAP = 0x04 | |
| COPY = 0x05 # duplicate nth from top | |
| ROT = 0x06 # rotate top 3 | |
| # Arithmetic | |
| ADD = 0x10 | |
| SUB = 0x11 | |
| MUL = 0x12 | |
| DIV = 0x13 | |
| MOD = 0x14 | |
| NEG = 0x15 | |
| ABS = 0x16 | |
| # Boolean (NAND-complete kernel) | |
| AND = 0x20 # NAND(NAND(a,b), NAND(a,b)) | |
| OR = 0x21 # NAND(NAND(a,a), NAND(b,b)) | |
| NOT = 0x22 # NAND(x, x) | |
| NAND = 0x23 # primitive | |
| XOR = 0x24 # NAND(NAND(a,NAND(a,b)), NAND(b,NAND(a,b))) | |
| XNOR = 0x25 | |
| NOR = 0x26 | |
| # Comparison | |
| EQ = 0x30 | |
| NEQ = 0x31 | |
| LT = 0x32 | |
| GT = 0x33 | |
| LE = 0x34 | |
| GE = 0x35 | |
| # Bitwise | |
| BAND = 0x38 | |
| BOR = 0x39 | |
| BXOR = 0x3A | |
| BNOT = 0x3B | |
| SHL = 0x3C | |
| SHR = 0x3D | |
| # Control flow | |
| JMP = 0x40 | |
| JZ = 0x41 # jump if top == 0 / False | |
| JNZ = 0x42 # jump if top != 0 / True | |
| CALL = 0x43 | |
| RET = 0x44 | |
| LOOP = 0x45 # loop: decrement top, jump if > 0 | |
| # Routing & dispatch | |
| ROUTE = 0x50 # route to expert by opcode arg | |
| DISPATCH = 0x51 # dispatch tool by opcode arg | |
| GATE = 0x52 # Jordan gate evaluation | |
| FILTER = 0x53 # entropy filter gate | |
| FORWARD = 0x54 # forward to next stage | |
| # Memory | |
| LOAD = 0x60 # load from memory address | |
| STORE = 0x61 # store to memory address | |
| ALLOC = 0x62 # allocate n bytes | |
| FREE = 0x63 | |
| # State / WORM | |
| COMMIT = 0x70 # commit state to WORM | |
| CHECKPOINT= 0x71 # save continuity checkpoint | |
| ROLLBACK = 0x72 # restore from checkpoint | |
| SEAL = 0x73 # seal current frame (WORM-protect) | |
| VERIFY = 0x74 # verify sealed frame | |
| # I/O | |
| PRINT = 0x80 # print top of stack | |
| READ = 0x81 # read value (stub) | |
| EMIT = 0x82 # emit to output buffer | |
| # Entropy management | |
| MEASURE = 0x90 # push current entropy value | |
| CLAMP = 0x91 # clamp top to [0.0, 0.20] | |
| ENTROPY = 0x92 # compute entropy of stack distribution | |
| # Halt | |
| HALT = 0xFF | |
| # --------------------------------------------------------------------------- | |
| # VMInstruction | |
| # --------------------------------------------------------------------------- | |
| class VMInstruction: | |
| opcode: VMOpcode | |
| arg: int = 0 | |
| symbol: str = '' | |
| lineno: int = 0 | |
| def __post_init__(self): | |
| if isinstance(self.opcode, int): | |
| self.opcode = VMOpcode(self.opcode) | |
| def __repr__(self) -> str: | |
| parts = [self.opcode.name] | |
| if self.arg != 0: | |
| parts.append(str(self.arg)) | |
| if self.symbol: | |
| parts.append(repr(self.symbol)) | |
| return f"VMInstruction({', '.join(parts)})" | |
| # --------------------------------------------------------------------------- | |
| # VMStack | |
| # --------------------------------------------------------------------------- | |
| class VMStackUnderflow(Exception): | |
| pass | |
| class VMStackOverflow(Exception): | |
| pass | |
| class VMStack: | |
| """LIFO stack with optional maximum depth limit.""" | |
| DEFAULT_MAX = 4096 | |
| def __init__(self, max_depth: int = DEFAULT_MAX): | |
| self._data: list[Any] = [] | |
| self._max_depth = max_depth | |
| def push(self, value: Any) -> None: | |
| if len(self._data) >= self._max_depth: | |
| raise VMStackOverflow( | |
| f"Stack overflow at depth {self._max_depth}" | |
| ) | |
| self._data.append(value) | |
| def pop(self) -> Any: | |
| if not self._data: | |
| raise VMStackUnderflow("Stack underflow: pop on empty stack") | |
| return self._data.pop() | |
| def peek(self, offset: int = 0) -> Any: | |
| """Peek at the top (offset=0) or nth item from top (offset=n).""" | |
| idx = -(offset + 1) | |
| if abs(idx) > len(self._data): | |
| raise VMStackUnderflow(f"Stack peek offset {offset} out of range") | |
| return self._data[idx] | |
| def peek_n(self, n: int) -> list[Any]: | |
| """Return top n items (bottom-first order).""" | |
| if n > len(self._data): | |
| raise VMStackUnderflow(f"Stack peek_n {n} > depth {len(self._data)}") | |
| return list(self._data[-n:]) | |
| def is_empty(self) -> bool: | |
| return len(self._data) == 0 | |
| def size(self) -> int: | |
| return len(self._data) | |
| def clear(self) -> None: | |
| self._data.clear() | |
| def as_list(self) -> list[Any]: | |
| return list(self._data) | |
| def to_display(self) -> str: | |
| if not self._data: | |
| return "[empty]" | |
| items = [repr(x) for x in reversed(self._data)] | |
| return "[" + ", ".join(items[:8]) + (", ..." if len(items) > 8 else "") + "]" | |
| # --------------------------------------------------------------------------- | |
| # VMRegisters | |
| # --------------------------------------------------------------------------- | |
| class VMRegisters: | |
| pc: int = 0 # program counter (instruction index) | |
| sp: int = 0 # shadow stack pointer (informational) | |
| flags: int = 0 # status flags: bit 0=zero, bit 1=carry, bit 2=overflow, bit 3=negative | |
| entropy: float = 0.0 # current running entropy estimate | |
| FLAG_ZERO = 1 << 0 | |
| FLAG_CARRY = 1 << 1 | |
| FLAG_OVERFLOW = 1 << 2 | |
| FLAG_NEGATIVE = 1 << 3 | |
| FLAG_HALT = 1 << 7 | |
| def set_zero(self, value: Any) -> None: | |
| if value == 0 or value is False: | |
| self.flags |= self.FLAG_ZERO | |
| else: | |
| self.flags &= ~self.FLAG_ZERO | |
| def set_negative(self, value: Any) -> None: | |
| try: | |
| if float(value) < 0: | |
| self.flags |= self.FLAG_NEGATIVE | |
| else: | |
| self.flags &= ~self.FLAG_NEGATIVE | |
| except (TypeError, ValueError): | |
| pass | |
| def is_zero(self) -> bool: | |
| return bool(self.flags & self.FLAG_ZERO) | |
| def is_halted(self) -> bool: | |
| return bool(self.flags & self.FLAG_HALT) | |
| def halt(self) -> None: | |
| self.flags |= self.FLAG_HALT | |
| def update(self, value: Any) -> None: | |
| self.set_zero(value) | |
| self.set_negative(value) | |
| # --------------------------------------------------------------------------- | |
| # VMMemory | |
| # --------------------------------------------------------------------------- | |
| class VMMemory: | |
| """ | |
| Simple 64KB address space memory for the VM. | |
| Byte-addressable, no protection. | |
| """ | |
| SIZE = 65536 # 64KB | |
| def __init__(self, size: int = SIZE): | |
| self._data = bytearray(size) | |
| self._size = size | |
| def read(self, addr: int) -> int: | |
| self._check(addr, 1) | |
| return self._data[addr] | |
| def write(self, addr: int, value: int) -> None: | |
| self._check(addr, 1) | |
| self._data[addr] = value & 0xFF | |
| def read_bytes(self, addr: int, n: int) -> bytes: | |
| self._check(addr, n) | |
| return bytes(self._data[addr:addr + n]) | |
| def write_bytes(self, addr: int, data: bytes) -> None: | |
| self._check(addr, len(data)) | |
| self._data[addr:addr + len(data)] = data | |
| def read_u32(self, addr: int) -> int: | |
| return struct.unpack_from('<I', self._data, addr)[0] | |
| def write_u32(self, addr: int, value: int) -> None: | |
| struct.pack_into('<I', self._data, addr, value & 0xFFFFFFFF) | |
| def read_u64(self, addr: int) -> int: | |
| return struct.unpack_from('<Q', self._data, addr)[0] | |
| def write_u64(self, addr: int, value: int) -> None: | |
| struct.pack_into('<Q', self._data, addr, value & 0xFFFFFFFFFFFFFFFF) | |
| def fill(self, addr: int, byte: int, n: int) -> None: | |
| self._check(addr, n) | |
| for i in range(n): | |
| self._data[addr + i] = byte & 0xFF | |
| def _check(self, addr: int, size: int) -> None: | |
| if addr < 0 or addr + size > self._size: | |
| raise VMError(f"Memory access out of bounds: addr={addr:#x}, size={size}") | |
| def size(self) -> int: | |
| return self._size | |
| def dump(self, addr: int = 0, length: int = 64) -> str: | |
| """Hex dump.""" | |
| lines = [] | |
| for off in range(0, length, 16): | |
| chunk = self._data[addr + off:addr + off + 16] | |
| hex_part = ' '.join(f'{b:02x}' for b in chunk) | |
| ascii_part = ''.join(chr(b) if 32 <= b < 127 else '.' for b in chunk) | |
| lines.append(f'{addr + off:04x} {hex_part:<48} |{ascii_part}|') | |
| return '\n'.join(lines) | |
| # --------------------------------------------------------------------------- | |
| # VMError | |
| # --------------------------------------------------------------------------- | |
| class VMError(Exception): | |
| pass | |
| class VMEntropyViolation(VMError): | |
| pass | |
| class VMHaltException(Exception): | |
| pass | |
| # --------------------------------------------------------------------------- | |
| # WORMLog — immutable append-only log for COMMIT / CHECKPOINT | |
| # --------------------------------------------------------------------------- | |
| class WORMEntry: | |
| seq: int | |
| timestamp_ns: int | |
| opcode: VMOpcode | |
| data: bytes | |
| checksum: bytes | |
| def verify(self) -> bool: | |
| expected = hashlib.blake2b(self.data, digest_size=32).digest() | |
| return expected == self.checksum | |
| class WORMLog: | |
| """Append-only log for VM state commits.""" | |
| def __init__(self): | |
| self._entries: list[WORMEntry] = [] | |
| self._seq = 0 | |
| def append(self, opcode: VMOpcode, data: bytes) -> WORMEntry: | |
| checksum = hashlib.blake2b(data, digest_size=32).digest() | |
| entry = WORMEntry( | |
| seq=self._seq, | |
| timestamp_ns=time.time_ns(), | |
| opcode=opcode, | |
| data=data, | |
| checksum=checksum, | |
| ) | |
| self._entries.append(entry) | |
| self._seq += 1 | |
| return entry | |
| def last(self) -> Optional[WORMEntry]: | |
| return self._entries[-1] if self._entries else None | |
| def count(self) -> int: | |
| return len(self._entries) | |
| def all_valid(self) -> bool: | |
| return all(e.verify() for e in self._entries) | |
| def export(self) -> list[dict]: | |
| return [ | |
| { | |
| 'seq': e.seq, | |
| 'timestamp_ns': e.timestamp_ns, | |
| 'opcode': e.opcode.name, | |
| 'data_len': len(e.data), | |
| 'checksum': e.checksum.hex(), | |
| 'valid': e.verify(), | |
| } | |
| for e in self._entries | |
| ] | |
| # --------------------------------------------------------------------------- | |
| # NAND-complete Boolean kernel (pure Python, no bit tricks) | |
| # --------------------------------------------------------------------------- | |
| def nand_op(a: Any, b: Any) -> int: | |
| """NAND gate — the universal primitive.""" | |
| ai = 1 if a else 0 | |
| bi = 1 if b else 0 | |
| return 1 - ai * bi # NAND(a,b) = NOT(a AND b) = 1 - a*b (when {0,1}) | |
| def nand_not(x: Any) -> int: | |
| return nand_op(x, x) | |
| def nand_and(a: Any, b: Any) -> int: | |
| n = nand_op(a, b) | |
| return nand_op(n, n) # NOT(NAND(a,b)) | |
| def nand_or(a: Any, b: Any) -> int: | |
| na = nand_op(a, a) # NOT a | |
| nb = nand_op(b, b) # NOT b | |
| return nand_op(na, nb) # NAND(NOT a, NOT b) = a OR b | |
| def nand_xor(a: Any, b: Any) -> int: | |
| ab = nand_op(a, b) | |
| a_ab = nand_op(a, ab) | |
| b_ab = nand_op(b, ab) | |
| return nand_op(a_ab, b_ab) | |
| def nand_xnor(a: Any, b: Any) -> int: | |
| return nand_not(nand_xor(a, b)) | |
| def nand_nor(a: Any, b: Any) -> int: | |
| return nand_not(nand_or(a, b)) | |
| # --------------------------------------------------------------------------- | |
| # Routing dispatch table | |
| # --------------------------------------------------------------------------- | |
| class DispatchTable: | |
| """ | |
| Maps opcodes to Python callables for ROUTE / DISPATCH instructions. | |
| """ | |
| def __init__(self): | |
| self._table: dict[int, Callable] = {} | |
| def register(self, opcode: int, handler: Callable) -> None: | |
| self._table[opcode] = handler | |
| def dispatch(self, opcode: int, *args) -> Any: | |
| handler = self._table.get(opcode) | |
| if handler is None: | |
| raise VMError(f"No handler registered for opcode {opcode:#04x}") | |
| return handler(*args) | |
| def has(self, opcode: int) -> bool: | |
| return opcode in self._table | |
| def count(self) -> int: | |
| return len(self._table) | |
| # --------------------------------------------------------------------------- | |
| # CallFrame | |
| # --------------------------------------------------------------------------- | |
| class CallFrame: | |
| return_pc: int | |
| local_vars: dict = field(default_factory=dict) | |
| saved_registers: VMRegisters = field(default_factory=VMRegisters) | |
| # --------------------------------------------------------------------------- | |
| # SovereignVM — main virtual machine | |
| # --------------------------------------------------------------------------- | |
| class SovereignVM: | |
| """ | |
| Minimal stack-based VM that executes VMInstruction programs. | |
| Features: | |
| - NAND-complete Boolean kernel | |
| - Entropy constraint enforcement (H <= 0.20 per DSL) | |
| - WORM commit / checkpoint via WORMLog | |
| - Routing dispatch table | |
| - 64KB memory space | |
| - Call/return stack for subroutines | |
| """ | |
| ENTROPY_LIMIT = 0.20 # DSL constraint | |
| def __init__( | |
| self, | |
| program: list[VMInstruction], | |
| dispatch_table: Optional[DispatchTable] = None, | |
| output_buffer: Optional[io.StringIO] = None, | |
| ): | |
| self._program = program | |
| self._stack = VMStack() | |
| self._registers = VMRegisters() | |
| self._memory = VMMemory() | |
| self._worm = WORMLog() | |
| self._call_stack: list[CallFrame] = [] | |
| self._local_vars: dict[str, Any] = {} | |
| self._dispatch = dispatch_table or DispatchTable() | |
| self._output = output_buffer or io.StringIO() | |
| self._checkpoints: list[dict] = [] | |
| self._step_count = 0 | |
| self._max_steps = 100_000 | |
| # --- execution core ----------------------------------------------------- | |
| def step(self) -> bool: | |
| """ | |
| Execute one instruction. | |
| Returns False if HALT was reached, True otherwise. | |
| """ | |
| pc = self._registers.pc | |
| if pc < 0 or pc >= len(self._program): | |
| self._registers.halt() | |
| return False | |
| instr = self._program[pc] | |
| self._registers.pc += 1 | |
| self._step_count += 1 | |
| try: | |
| self._execute(instr) | |
| except VMHaltException: | |
| self._registers.halt() | |
| return False | |
| except VMEntropyViolation: | |
| raise | |
| except VMStackUnderflow as exc: | |
| raise VMError(f"Stack underflow at pc={pc}: {exc}") from exc | |
| return not self._registers.is_halted() | |
| def run(self, max_steps: int = 10_000) -> Any: | |
| """ | |
| Run for up to max_steps instructions. | |
| Returns top of stack, or None if stack is empty. | |
| """ | |
| self._max_steps = max_steps | |
| steps = 0 | |
| while steps < max_steps: | |
| if not self.step(): | |
| break | |
| steps += 1 | |
| else: | |
| raise VMError(f"VM exceeded max_steps={max_steps}") | |
| return self._stack.peek() if not self._stack.is_empty() else None | |
| def run_until_halt(self) -> Any: | |
| return self.run(max_steps=self._max_steps) | |
| def get_registers(self) -> VMRegisters: | |
| return VMRegisters( | |
| pc=self._registers.pc, | |
| sp=self._stack.size(), | |
| flags=self._registers.flags, | |
| entropy=self._registers.entropy, | |
| ) | |
| def get_stack(self) -> list: | |
| return self._stack.as_list() | |
| def reset(self) -> None: | |
| """Reset VM to initial state.""" | |
| self._stack.clear() | |
| self._registers = VMRegisters() | |
| self._memory = VMMemory() | |
| self._call_stack.clear() | |
| self._local_vars.clear() | |
| self._checkpoints.clear() | |
| self._step_count = 0 | |
| def check_entropy_constraint(self) -> bool: | |
| """DSL constraint: H <= 0.20""" | |
| return self._registers.entropy <= self.ENTROPY_LIMIT | |
| def compute_entropy(self) -> float: | |
| """ | |
| Shannon entropy of stack value distribution. | |
| H = -sum(p * ln(p)) | |
| Normalized to [0.0, 1.0] by dividing by ln(N). | |
| """ | |
| data = self._stack.as_list() | |
| if len(data) < 2: | |
| return 0.0 | |
| # Count occurrences (hash-based) | |
| counts: dict = {} | |
| for v in data: | |
| key = type(v).__name__ + ':' + str(v)[:32] | |
| counts[key] = counts.get(key, 0) + 1 | |
| n = len(data) | |
| h = 0.0 | |
| for cnt in counts.values(): | |
| p = cnt / n | |
| if p > 0: | |
| h -= p * math.log(p) | |
| # Normalize to [0, 1] | |
| max_h = math.log(n) if n > 1 else 1.0 | |
| return h / max_h if max_h > 0 else 0.0 | |
| # --- instruction execution ---------------------------------------------- | |
| def _execute(self, instr: VMInstruction) -> None: | |
| op = instr.opcode | |
| arg = instr.arg | |
| sym = instr.symbol | |
| # ---- Stack primitives ---- | |
| if op == VMOpcode.NOP: | |
| pass | |
| elif op == VMOpcode.PUSH: | |
| # Push arg as integer, or symbol as string if symbol is set | |
| self._stack.push(sym if sym else arg) | |
| self._update_entropy() | |
| elif op == VMOpcode.POP: | |
| self._stack.pop() | |
| elif op == VMOpcode.DUP: | |
| self._stack.push(self._stack.peek()) | |
| elif op == VMOpcode.COPY: | |
| self._stack.push(self._stack.peek(arg)) | |
| elif op == VMOpcode.SWAP: | |
| a = self._stack.pop() | |
| b = self._stack.pop() | |
| self._stack.push(a) | |
| self._stack.push(b) | |
| elif op == VMOpcode.ROT: | |
| c = self._stack.pop() | |
| b = self._stack.pop() | |
| a = self._stack.pop() | |
| self._stack.push(b) | |
| self._stack.push(c) | |
| self._stack.push(a) | |
| # ---- Arithmetic ---- | |
| elif op == VMOpcode.ADD: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| result = self._coerce(a) + self._coerce(b) | |
| self._stack.push(result) | |
| self._registers.update(result) | |
| elif op == VMOpcode.SUB: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| result = self._coerce(a) - self._coerce(b) | |
| self._stack.push(result) | |
| self._registers.update(result) | |
| elif op == VMOpcode.MUL: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| result = self._coerce(a) * self._coerce(b) | |
| self._stack.push(result) | |
| self._registers.update(result) | |
| elif op == VMOpcode.DIV: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| bf, af = self._coerce_f(b), self._coerce_f(a) | |
| if bf == 0.0: | |
| raise VMError("Division by zero") | |
| result = af / bf | |
| self._stack.push(result) | |
| self._registers.update(result) | |
| elif op == VMOpcode.MOD: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| bi, ai = int(self._coerce(b)), int(self._coerce(a)) | |
| if bi == 0: | |
| raise VMError("Modulo by zero") | |
| self._stack.push(ai % bi) | |
| elif op == VMOpcode.NEG: | |
| a = self._stack.pop() | |
| self._stack.push(-self._coerce(a)) | |
| elif op == VMOpcode.ABS: | |
| a = self._stack.pop() | |
| self._stack.push(abs(self._coerce(a))) | |
| # ---- Boolean (NAND-complete kernel) ---- | |
| elif op == VMOpcode.NAND: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(nand_op(a, b)) | |
| elif op == VMOpcode.NOT: | |
| a = self._stack.pop() | |
| self._stack.push(nand_not(a)) | |
| elif op == VMOpcode.AND: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(nand_and(a, b)) | |
| elif op == VMOpcode.OR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(nand_or(a, b)) | |
| elif op == VMOpcode.XOR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(nand_xor(a, b)) | |
| elif op == VMOpcode.XNOR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(nand_xnor(a, b)) | |
| elif op == VMOpcode.NOR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(nand_nor(a, b)) | |
| # ---- Comparison ---- | |
| elif op == VMOpcode.EQ: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(1 if a == b else 0) | |
| elif op == VMOpcode.NEQ: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(1 if a != b else 0) | |
| elif op == VMOpcode.LT: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(1 if self._coerce(a) < self._coerce(b) else 0) | |
| elif op == VMOpcode.GT: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(1 if self._coerce(a) > self._coerce(b) else 0) | |
| elif op == VMOpcode.LE: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(1 if self._coerce(a) <= self._coerce(b) else 0) | |
| elif op == VMOpcode.GE: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(1 if self._coerce(a) >= self._coerce(b) else 0) | |
| # ---- Bitwise ---- | |
| elif op == VMOpcode.BAND: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(int(self._coerce(a)) & int(self._coerce(b))) | |
| elif op == VMOpcode.BOR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(int(self._coerce(a)) | int(self._coerce(b))) | |
| elif op == VMOpcode.BXOR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(int(self._coerce(a)) ^ int(self._coerce(b))) | |
| elif op == VMOpcode.BNOT: | |
| a = self._stack.pop() | |
| self._stack.push(~int(self._coerce(a))) | |
| elif op == VMOpcode.SHL: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(int(self._coerce(a)) << (int(self._coerce(b)) & 63)) | |
| elif op == VMOpcode.SHR: | |
| b, a = self._stack.pop(), self._stack.pop() | |
| self._stack.push(int(self._coerce(a)) >> (int(self._coerce(b)) & 63)) | |
| # ---- Control flow ---- | |
| elif op == VMOpcode.JMP: | |
| self._registers.pc = arg | |
| elif op == VMOpcode.JZ: | |
| top = self._stack.peek() | |
| if not top or top == 0: | |
| self._registers.pc = arg | |
| elif op == VMOpcode.JNZ: | |
| top = self._stack.peek() | |
| if top and top != 0: | |
| self._registers.pc = arg | |
| elif op == VMOpcode.CALL: | |
| frame = CallFrame( | |
| return_pc=self._registers.pc, | |
| local_vars=dict(self._local_vars), | |
| saved_registers=VMRegisters( | |
| pc=self._registers.pc, | |
| sp=self._stack.size(), | |
| flags=self._registers.flags, | |
| entropy=self._registers.entropy, | |
| ), | |
| ) | |
| self._call_stack.append(frame) | |
| self._registers.pc = arg | |
| elif op == VMOpcode.RET: | |
| if not self._call_stack: | |
| raise VMHaltException("RETURN with empty call stack") | |
| frame = self._call_stack.pop() | |
| self._registers.pc = frame.return_pc | |
| self._local_vars = frame.local_vars | |
| elif op == VMOpcode.LOOP: | |
| count = self._stack.pop() | |
| count = int(self._coerce(count)) - 1 | |
| if count > 0: | |
| self._stack.push(count) | |
| self._registers.pc = arg | |
| # else: loop exits naturally | |
| # ---- Routing ---- | |
| elif op == VMOpcode.ROUTE: | |
| if self._dispatch.has(arg): | |
| top = self._stack.peek() if not self._stack.is_empty() else None | |
| result = self._dispatch.dispatch(arg, top) | |
| if result is not None: | |
| self._stack.push(result) | |
| # If no handler: passthrough (soft routing) | |
| elif op == VMOpcode.DISPATCH: | |
| args_list = [] | |
| n_args = arg | |
| for _ in range(n_args): | |
| args_list.insert(0, self._stack.pop()) | |
| opcode_val = int(args_list[0]) if args_list else 0 | |
| result = None | |
| if self._dispatch.has(opcode_val): | |
| result = self._dispatch.dispatch(opcode_val, *args_list[1:]) | |
| if result is not None: | |
| self._stack.push(result) | |
| elif op == VMOpcode.GATE: | |
| """Jordan gate: evaluate |ψ⟩ under Φ^-2 entropy bound.""" | |
| top = self._stack.peek() if not self._stack.is_empty() else 0 | |
| entropy = self.compute_entropy() | |
| # Gate passes if entropy <= PHI^-2 ≈ 0.382 | |
| phi_sq_inv = (math.sqrt(5) - 1) / 2 # approx 0.618, but use phi^-2 | |
| phi_sq_inv = 1.0 / (((1 + math.sqrt(5)) / 2) ** 2) # phi^-2 ≈ 0.382 | |
| gate_result = 1 if entropy <= phi_sq_inv else 0 | |
| self._stack.push(gate_result) | |
| elif op == VMOpcode.FILTER: | |
| """Entropy filter gate — enforce DSL H <= 0.20.""" | |
| entropy = self.compute_entropy() | |
| self._registers.entropy = entropy | |
| if entropy > self.ENTROPY_LIMIT: | |
| # Drain high-entropy items | |
| while self._stack.size() > 1 and self.compute_entropy() > self.ENTROPY_LIMIT: | |
| self._stack.pop() | |
| elif op == VMOpcode.FORWARD: | |
| # No-op in this VM — downstream pipeline handles forwarding | |
| pass | |
| # ---- Memory ---- | |
| elif op == VMOpcode.LOAD: | |
| addr = int(self._stack.pop()) | |
| self._stack.push(self._memory.read(addr)) | |
| elif op == VMOpcode.STORE: | |
| value = self._stack.pop() | |
| addr = int(self._stack.pop()) | |
| self._memory.write(addr, int(self._coerce(value))) | |
| elif op == VMOpcode.ALLOC: | |
| # Stub: push 0 (address of allocation) | |
| self._stack.push(0) | |
| elif op == VMOpcode.FREE: | |
| self._stack.pop() # discard address | |
| # ---- WORM / State ---- | |
| elif op == VMOpcode.COMMIT: | |
| snapshot = self._serialize_state() | |
| entry = self._worm.append(VMOpcode.COMMIT, snapshot) | |
| self._stack.push(entry.seq) | |
| elif op == VMOpcode.CHECKPOINT: | |
| cp = { | |
| 'pc': self._registers.pc, | |
| 'flags': self._registers.flags, | |
| 'entropy': self._registers.entropy, | |
| 'stack': list(self._stack.as_list()), | |
| 'locals': dict(self._local_vars), | |
| 'timestamp_ns': time.time_ns(), | |
| } | |
| self._checkpoints.append(cp) | |
| self._stack.push(len(self._checkpoints) - 1) | |
| elif op == VMOpcode.ROLLBACK: | |
| cp_idx = int(self._stack.pop()) if not self._stack.is_empty() else -1 | |
| if self._checkpoints: | |
| idx = cp_idx if 0 <= cp_idx < len(self._checkpoints) else -1 | |
| cp = self._checkpoints[idx] | |
| self._stack.clear() | |
| for v in cp['stack']: | |
| self._stack.push(v) | |
| self._registers.pc = cp['pc'] | |
| self._registers.flags = cp['flags'] | |
| self._registers.entropy = cp['entropy'] | |
| self._local_vars = dict(cp['locals']) | |
| elif op == VMOpcode.SEAL: | |
| snapshot = self._serialize_state() | |
| self._worm.append(VMOpcode.SEAL, snapshot) | |
| elif op == VMOpcode.VERIFY: | |
| valid = self._worm.all_valid() | |
| self._stack.push(1 if valid else 0) | |
| # ---- I/O ---- | |
| elif op == VMOpcode.PRINT: | |
| value = self._stack.peek() if not self._stack.is_empty() else None | |
| self._output.write(repr(value) + '\n') | |
| elif op == VMOpcode.READ: | |
| self._stack.push(0) # stub | |
| elif op == VMOpcode.EMIT: | |
| value = self._stack.pop() | |
| self._output.write(repr(value)) | |
| # ---- Entropy management ---- | |
| elif op == VMOpcode.MEASURE: | |
| entropy = self.compute_entropy() | |
| self._registers.entropy = entropy | |
| self._stack.push(entropy) | |
| elif op == VMOpcode.CLAMP: | |
| top = self._stack.pop() | |
| try: | |
| v = float(top) | |
| self._stack.push(max(0.0, min(self.ENTROPY_LIMIT, v))) | |
| except (TypeError, ValueError): | |
| self._stack.push(0.0) | |
| elif op == VMOpcode.ENTROPY: | |
| entropy = self.compute_entropy() | |
| self._registers.entropy = entropy | |
| self._stack.push(entropy) | |
| # ---- Halt ---- | |
| elif op == VMOpcode.HALT: | |
| raise VMHaltException("HALT instruction reached") | |
| else: | |
| raise VMError(f"Unknown opcode: {op!r}") | |
| # --- helpers ------------------------------------------------------------ | |
| def _coerce(self, v: Any) -> Any: | |
| """Coerce value to numeric type.""" | |
| if isinstance(v, (int, float)): | |
| return v | |
| if isinstance(v, bool): | |
| return 1 if v else 0 | |
| if isinstance(v, str): | |
| try: | |
| return int(v) | |
| except ValueError: | |
| try: | |
| return float(v) | |
| except ValueError: | |
| return 0 | |
| return 0 | |
| def _coerce_f(self, v: Any) -> float: | |
| return float(self._coerce(v)) | |
| def _update_entropy(self) -> None: | |
| if self._stack.size() >= 4: | |
| self._registers.entropy = self.compute_entropy() | |
| if self._registers.entropy > self.ENTROPY_LIMIT: | |
| raise VMEntropyViolation( | |
| f"Entropy {self._registers.entropy:.4f} exceeds " | |
| f"limit {self.ENTROPY_LIMIT}" | |
| ) | |
| def _serialize_state(self) -> bytes: | |
| """Serialize current VM state to bytes for WORM commitment.""" | |
| buf = io.BytesIO() | |
| # Header | |
| buf.write(struct.pack('>Q', time.time_ns())) | |
| buf.write(struct.pack('>I', self._registers.pc)) | |
| buf.write(struct.pack('>I', self._registers.flags)) | |
| buf.write(struct.pack('>d', self._registers.entropy)) | |
| # Stack depth | |
| stack_data = self._stack.as_list() | |
| buf.write(struct.pack('>H', len(stack_data))) | |
| # Top 16 items as string repr | |
| for item in stack_data[:16]: | |
| encoded = repr(item).encode('utf-8')[:64] | |
| buf.write(struct.pack('>H', len(encoded))) | |
| buf.write(encoded) | |
| return buf.getvalue() | |
| def output(self) -> str: | |
| """Return captured output.""" | |
| return self._output.getvalue() | |
| def worm_log(self) -> WORMLog: | |
| return self._worm | |
| def step_count(self) -> int: | |
| return self._step_count | |
| def stats(self) -> dict: | |
| return { | |
| 'steps': self._step_count, | |
| 'stack_depth': self._stack.size(), | |
| 'pc': self._registers.pc, | |
| 'entropy': self._registers.entropy, | |
| 'worm_entries': self._worm.count(), | |
| 'checkpoints': len(self._checkpoints), | |
| 'entropy_compliant': self.check_entropy_constraint(), | |
| } | |
| # --------------------------------------------------------------------------- | |
| # VMAssembler — text-format assembler | |
| # --------------------------------------------------------------------------- | |
| class VMAssembler: | |
| """ | |
| Parses a simple text assembly language into VMInstruction lists. | |
| Grammar: | |
| OPCODE [arg] [; comment] | |
| LABEL: | |
| """ | |
| def assemble(self, source: str) -> list[VMInstruction]: | |
| """Parse text assembly to VMInstruction list.""" | |
| instructions = [] | |
| labels: dict[str, int] = {} | |
| pending_jumps: list[tuple[int, str]] = [] # (idx, label_name) | |
| lines = source.splitlines() | |
| for line in lines: | |
| line = line.strip() | |
| if not line or line.startswith(';') or line.startswith('#'): | |
| continue | |
| # Strip inline comments | |
| line = line.split(';')[0].strip() | |
| if not line: | |
| continue | |
| # Label definition | |
| if line.endswith(':'): | |
| labels[line[:-1].strip()] = len(instructions) | |
| continue | |
| parts = line.split(None, 2) | |
| opcode_name = parts[0].upper() | |
| try: | |
| opcode = VMOpcode[opcode_name] | |
| except KeyError: | |
| raise VMError(f"Unknown opcode: {opcode_name!r}") | |
| arg = 0 | |
| sym = '' | |
| if len(parts) > 1: | |
| raw_arg = parts[1].strip().strip('"\'') | |
| # Check if it's a label reference | |
| if raw_arg.isidentifier() and not raw_arg.startswith('0x'): | |
| sym = raw_arg | |
| pending_jumps.append((len(instructions), raw_arg)) | |
| else: | |
| try: | |
| arg = int(raw_arg, 0) | |
| except ValueError: | |
| sym = raw_arg | |
| if len(parts) > 2: | |
| sym = parts[2].strip().strip('"\'') | |
| instructions.append(VMInstruction(opcode=opcode, arg=arg, symbol=sym)) | |
| # Resolve label references | |
| for idx, label_name in pending_jumps: | |
| if label_name in labels: | |
| instructions[idx].arg = labels[label_name] | |
| instructions[idx].symbol = '' | |
| # else: leave as symbol (might be a dispatch name) | |
| return instructions | |
| def disassemble(self, instructions: list[VMInstruction]) -> str: | |
| """Convert VMInstruction list to text assembly.""" | |
| lines = [] | |
| for i, instr in enumerate(instructions): | |
| parts = [f'{i:4d}: {instr.opcode.name:<12}'] | |
| if instr.arg != 0: | |
| parts.append(f'{instr.arg}') | |
| if instr.symbol: | |
| parts.append(repr(instr.symbol)) | |
| lines.append(' '.join(parts)) | |
| return '\n'.join(lines) | |
| # --------------------------------------------------------------------------- | |
| # Program builders (convenience functions) | |
| # --------------------------------------------------------------------------- | |
| def make_program(*spec: tuple) -> list[VMInstruction]: | |
| """ | |
| Build a program from (opcode, arg, symbol) tuples. | |
| arg and symbol are optional. | |
| """ | |
| instructions = [] | |
| for item in spec: | |
| if isinstance(item, VMInstruction): | |
| instructions.append(item) | |
| elif isinstance(item, tuple): | |
| op = item[0] | |
| arg = item[1] if len(item) > 1 else 0 | |
| sym = item[2] if len(item) > 2 else '' | |
| if isinstance(op, (str,)): | |
| op = VMOpcode[op.upper()] | |
| instructions.append(VMInstruction(opcode=op, arg=arg, symbol=sym)) | |
| elif isinstance(item, VMOpcode): | |
| instructions.append(VMInstruction(opcode=item)) | |
| return instructions | |
| def push(value: Any) -> VMInstruction: | |
| if isinstance(value, str): | |
| return VMInstruction(VMOpcode.PUSH, 0, value) | |
| return VMInstruction(VMOpcode.PUSH, int(value) if isinstance(value, (int, float)) else 0, | |
| str(value) if not isinstance(value, (int, float)) else '') | |
| def halt() -> VMInstruction: | |
| return VMInstruction(VMOpcode.HALT) | |
| def commit() -> VMInstruction: | |
| return VMInstruction(VMOpcode.COMMIT) | |
| # --------------------------------------------------------------------------- | |
| # Self-test | |
| # --------------------------------------------------------------------------- | |
| def _self_test() -> bool: | |
| # Test NAND kernel | |
| assert nand_op(0, 0) == 1 | |
| assert nand_op(0, 1) == 1 | |
| assert nand_op(1, 0) == 1 | |
| assert nand_op(1, 1) == 0 | |
| assert nand_not(0) == 1 | |
| assert nand_not(1) == 0 | |
| assert nand_and(1, 1) == 1 | |
| assert nand_and(1, 0) == 0 | |
| assert nand_and(0, 0) == 0 | |
| assert nand_or(0, 0) == 0 | |
| assert nand_or(1, 0) == 1 | |
| assert nand_or(1, 1) == 1 | |
| assert nand_xor(0, 0) == 0 | |
| assert nand_xor(1, 0) == 1 | |
| assert nand_xor(1, 1) == 0 | |
| # Test VMStack | |
| stack = VMStack() | |
| stack.push(1) | |
| stack.push(2) | |
| assert stack.peek() == 2 | |
| assert stack.pop() == 2 | |
| assert stack.size() == 1 | |
| # Test simple VM program: compute 3 + 4 | |
| program = [ | |
| VMInstruction(VMOpcode.PUSH, 3), | |
| VMInstruction(VMOpcode.PUSH, 4), | |
| VMInstruction(VMOpcode.ADD), | |
| VMInstruction(VMOpcode.HALT), | |
| ] | |
| vm = SovereignVM(program) | |
| result = vm.run() | |
| assert result == 7, f"Expected 7, got {result}" | |
| # Test NAND in VM | |
| nand_prog = [ | |
| VMInstruction(VMOpcode.PUSH, 1), | |
| VMInstruction(VMOpcode.PUSH, 1), | |
| VMInstruction(VMOpcode.NAND), | |
| VMInstruction(VMOpcode.HALT), | |
| ] | |
| vm2 = SovereignVM(nand_prog) | |
| result2 = vm2.run() | |
| assert result2 == 0, f"NAND(1,1) should be 0, got {result2}" | |
| # Test CHECKPOINT + COMMIT | |
| cp_prog = [ | |
| VMInstruction(VMOpcode.PUSH, 42), | |
| VMInstruction(VMOpcode.CHECKPOINT), | |
| VMInstruction(VMOpcode.POP), # remove checkpoint index | |
| VMInstruction(VMOpcode.COMMIT), | |
| VMInstruction(VMOpcode.HALT), | |
| ] | |
| vm3 = SovereignVM(cp_prog) | |
| vm3.run() | |
| assert vm3.worm_log().count() >= 1 | |
| # Test assembler | |
| asm = VMAssembler() | |
| prog_text = """ | |
| PUSH 10 | |
| PUSH 20 | |
| ADD | |
| HALT | |
| """ | |
| instrs = asm.assemble(prog_text) | |
| assert len(instrs) == 4 | |
| vm4 = SovereignVM(instrs) | |
| result4 = vm4.run() | |
| assert result4 == 30 | |
| # Test entropy constraint | |
| entropy_prog = [ | |
| VMInstruction(VMOpcode.ENTROPY), | |
| VMInstruction(VMOpcode.HALT), | |
| ] | |
| vm5 = SovereignVM(entropy_prog) | |
| result5 = vm5.run() | |
| assert isinstance(result5, float) | |
| return True | |
| # --------------------------------------------------------------------------- | |
| # VMProfiler — instruction-level profiling | |
| # --------------------------------------------------------------------------- | |
| class VMProfile: | |
| """Runtime profiling data collected from VM execution.""" | |
| instruction_counts: dict = field(default_factory=dict) | |
| total_steps: int = 0 | |
| total_time_ns: int = 0 | |
| worm_commits: int = 0 | |
| checkpoints: int = 0 | |
| peak_stack_depth: int = 0 | |
| entropy_violations: int = 0 | |
| entropy_samples: list = field(default_factory=list) | |
| def record(self, opcode: VMOpcode, stack_depth: int) -> None: | |
| name = opcode.name | |
| self.instruction_counts[name] = self.instruction_counts.get(name, 0) + 1 | |
| self.total_steps += 1 | |
| if stack_depth > self.peak_stack_depth: | |
| self.peak_stack_depth = stack_depth | |
| def top_instructions(self, n: int = 10) -> list[tuple[str, int]]: | |
| return sorted(self.instruction_counts.items(), key=lambda x: -x[1])[:n] | |
| def summary(self) -> str: | |
| lines = [ | |
| f"VMProfile: {self.total_steps} steps", | |
| f" Peak stack depth: {self.peak_stack_depth}", | |
| f" WORM commits: {self.worm_commits}", | |
| f" Checkpoints: {self.checkpoints}", | |
| f" Entropy violations: {self.entropy_violations}", | |
| f" Top instructions:", | |
| ] | |
| for name, count in self.top_instructions(5): | |
| pct = count / self.total_steps * 100 if self.total_steps else 0 | |
| lines.append(f" {name:<15} {count:>6} ({pct:.1f}%)") | |
| return '\n'.join(lines) | |
| class ProfilingVM(SovereignVM): | |
| """ | |
| SovereignVM subclass that collects profiling data during execution. | |
| """ | |
| def __init__(self, program: list[VMInstruction], **kwargs): | |
| super().__init__(program, **kwargs) | |
| self._profile = VMProfile() | |
| self._start_ns: int = 0 | |
| def run(self, max_steps: int = 10_000) -> Any: | |
| self._start_ns = time.time_ns() | |
| result = super().run(max_steps=max_steps) | |
| self._profile.total_time_ns = time.time_ns() - self._start_ns | |
| return result | |
| def step(self) -> bool: | |
| pc = self._registers.pc | |
| if 0 <= pc < len(self._program): | |
| instr = self._program[pc] | |
| self._profile.record(instr.opcode, self._stack.size()) | |
| result = super().step() | |
| if not result: | |
| self._profile.worm_commits = self._worm.count() | |
| self._profile.checkpoints = len(self._checkpoints) | |
| return result | |
| def profile(self) -> VMProfile: | |
| return self._profile | |
| # --------------------------------------------------------------------------- | |
| # VMDebugger — interactive debugging interface | |
| # --------------------------------------------------------------------------- | |
| class VMDebugger: | |
| """ | |
| Provides debugging facilities for SovereignVM programs. | |
| Supports breakpoints, single-step, watch expressions. | |
| """ | |
| def __init__(self, vm: SovereignVM): | |
| self._vm = vm | |
| self._breakpoints: set[int] = set() | |
| self._watchpoints: dict[str, Any] = {} # name -> previous value | |
| self._trace: list[dict] = [] | |
| self._max_trace = 1000 | |
| def add_breakpoint(self, pc: int) -> None: | |
| self._breakpoints.add(pc) | |
| def remove_breakpoint(self, pc: int) -> None: | |
| self._breakpoints.discard(pc) | |
| def watch(self, name: str, getter: Callable) -> None: | |
| """Watch a named value computed by getter(vm) at each step.""" | |
| self._watchpoints[name] = (getter, None) | |
| def run_to_breakpoint(self, max_steps: int = 100_000) -> Optional[int]: | |
| """ | |
| Run until a breakpoint is hit or max_steps reached. | |
| Returns the PC where execution stopped, or None if halted. | |
| """ | |
| steps = 0 | |
| while steps < max_steps: | |
| pc = self._vm._registers.pc | |
| if pc in self._breakpoints and steps > 0: | |
| return pc | |
| # Collect trace entry | |
| if len(self._trace) < self._max_trace: | |
| entry = { | |
| 'step': self._vm.step_count(), | |
| 'pc': pc, | |
| 'stack': self._vm._stack.as_list()[:4], | |
| 'entropy': self._vm._registers.entropy, | |
| } | |
| # Check watchpoints | |
| for name, (getter, prev) in list(self._watchpoints.items()): | |
| try: | |
| current = getter(self._vm) | |
| except Exception: | |
| current = None | |
| if current != prev: | |
| entry[f'watch:{name}'] = {'old': prev, 'new': current} | |
| self._watchpoints[name] = (getter, current) | |
| self._trace.append(entry) | |
| if not self._vm.step(): | |
| return None | |
| steps += 1 | |
| return None | |
| def step_once(self) -> bool: | |
| """Execute one instruction.""" | |
| return self._vm.step() | |
| def dump_trace(self, last_n: int = 20) -> str: | |
| """Return the last N trace entries as human-readable text.""" | |
| entries = self._trace[-last_n:] | |
| lines = [f"VMDebugger trace (last {len(entries)} entries):"] | |
| for entry in entries: | |
| stack_str = str(entry.get('stack', []))[:40] | |
| lines.append( | |
| f" step={entry['step']:5d} pc={entry['pc']:4d} " | |
| f"stack={stack_str} H={entry['entropy']:.4f}" | |
| ) | |
| for k, v in entry.items(): | |
| if k.startswith('watch:'): | |
| lines.append(f" {k}: {v}") | |
| return '\n'.join(lines) | |
| def clear_trace(self) -> None: | |
| self._trace.clear() | |
| def state_at(self, step: int) -> Optional[dict]: | |
| for entry in self._trace: | |
| if entry['step'] == step: | |
| return entry | |
| return None | |
| # --------------------------------------------------------------------------- | |
| # VMBenchmark — measure VM performance | |
| # --------------------------------------------------------------------------- | |
| class VMBenchmark: | |
| """ | |
| Benchmarks the VM on standard programs. | |
| Reports instructions per second and overhead per instruction. | |
| """ | |
| def run_nop_loop(self, count: int = 10_000) -> dict: | |
| """Benchmark: execute `count` NOPs.""" | |
| program = ( | |
| [VMInstruction(VMOpcode.PUSH, count)] + | |
| [VMInstruction(VMOpcode.NOP)] * min(count, 1000) + | |
| [VMInstruction(VMOpcode.HALT)] | |
| ) | |
| vm = SovereignVM(program) | |
| start = time.time_ns() | |
| vm.run(max_steps=count + 10) | |
| elapsed_ns = time.time_ns() - start | |
| steps = vm.step_count() | |
| ips = steps / (elapsed_ns / 1e9) if elapsed_ns > 0 else 0.0 | |
| return { | |
| 'steps': steps, | |
| 'elapsed_ns': elapsed_ns, | |
| 'ips': ips, | |
| 'ns_per_step': elapsed_ns / steps if steps > 0 else 0, | |
| } | |
| def run_arithmetic(self, count: int = 1000) -> dict: | |
| """Benchmark: additions in a tight loop.""" | |
| program = [] | |
| for i in range(count): | |
| program.append(VMInstruction(VMOpcode.PUSH, i)) | |
| if i > 0: | |
| program.append(VMInstruction(VMOpcode.ADD)) | |
| program.append(VMInstruction(VMOpcode.HALT)) | |
| vm = SovereignVM(program) | |
| start = time.time_ns() | |
| result = vm.run(max_steps=count * 3) | |
| elapsed_ns = time.time_ns() - start | |
| return { | |
| 'result': result, | |
| 'steps': vm.step_count(), | |
| 'elapsed_ns': elapsed_ns, | |
| 'ips': vm.step_count() / (elapsed_ns / 1e9) if elapsed_ns > 0 else 0.0, | |
| } | |
| def run_boolean(self, count: int = 1000) -> dict: | |
| """Benchmark: NAND operations.""" | |
| program = [] | |
| for i in range(count): | |
| program.append(VMInstruction(VMOpcode.PUSH, i & 1)) | |
| program.append(VMInstruction(VMOpcode.PUSH, (i >> 1) & 1)) | |
| program.append(VMInstruction(VMOpcode.NAND)) | |
| program.append(VMInstruction(VMOpcode.HALT)) | |
| vm = SovereignVM(program) | |
| start = time.time_ns() | |
| result = vm.run(max_steps=count * 4) | |
| elapsed_ns = time.time_ns() - start | |
| return { | |
| 'result': result, | |
| 'steps': vm.step_count(), | |
| 'elapsed_ns': elapsed_ns, | |
| } | |
| # --------------------------------------------------------------------------- | |
| # VMProgram — named program container with metadata | |
| # --------------------------------------------------------------------------- | |
| class VMProgram: | |
| """A named, versioned VM program with metadata.""" | |
| name: str | |
| version: str | |
| instructions: list[VMInstruction] | |
| description: str = "" | |
| author: str = "" | |
| created_ns: int = field(default_factory=time.time_ns) | |
| checksum: str = field(default="") | |
| def __post_init__(self): | |
| if not self.checksum: | |
| self.checksum = self._compute_checksum() | |
| def _compute_checksum(self) -> str: | |
| payload = self.name + self.version + str(len(self.instructions)) | |
| for instr in self.instructions: | |
| payload += f"{instr.opcode.value}{instr.arg}{instr.symbol}" | |
| return hashlib.blake2b(payload.encode(), digest_size=16).hexdigest() | |
| def build_vm(self, **kwargs) -> SovereignVM: | |
| return SovereignVM(self.instructions, **kwargs) | |
| def run(self, max_steps: int = 10_000) -> Any: | |
| vm = self.build_vm() | |
| return vm.run(max_steps=max_steps) | |
| def instruction_count(self) -> int: | |
| return len(self.instructions) | |
| def to_dict(self) -> dict: | |
| return { | |
| 'name': self.name, | |
| 'version': self.version, | |
| 'description': self.description, | |
| 'author': self.author, | |
| 'created_ns': self.created_ns, | |
| 'checksum': self.checksum, | |
| 'instructions': [ | |
| { | |
| 'opcode': i.opcode.name, | |
| 'arg': i.arg, | |
| 'symbol': i.symbol, | |
| } | |
| for i in self.instructions | |
| ], | |
| } | |
| def from_dict(cls, d: dict) -> 'VMProgram': | |
| instructions = [ | |
| VMInstruction( | |
| opcode=VMOpcode[i['opcode']], | |
| arg=i.get('arg', 0), | |
| symbol=i.get('symbol', ''), | |
| ) | |
| for i in d.get('instructions', []) | |
| ] | |
| return cls( | |
| name=d['name'], | |
| version=d.get('version', '0.0.1'), | |
| instructions=instructions, | |
| description=d.get('description', ''), | |
| author=d.get('author', ''), | |
| ) | |
| def from_source(cls, name: str, source: str, **kwargs) -> 'VMProgram': | |
| """Assemble from text source.""" | |
| asm = VMAssembler() | |
| instructions = asm.assemble(source) | |
| return cls(name=name, version="1.0.0", instructions=instructions, **kwargs) | |
| # --------------------------------------------------------------------------- | |
| # Standard library programs | |
| # --------------------------------------------------------------------------- | |
| def make_sum_program(values: list[int]) -> VMProgram: | |
| """Build a program that pushes all values and sums them.""" | |
| instructions = [] | |
| if not values: | |
| instructions.append(VMInstruction(VMOpcode.PUSH, 0)) | |
| else: | |
| for v in values: | |
| instructions.append(VMInstruction(VMOpcode.PUSH, v)) | |
| for _ in range(len(values) - 1): | |
| instructions.append(VMInstruction(VMOpcode.ADD)) | |
| instructions.append(VMInstruction(VMOpcode.HALT)) | |
| return VMProgram("sum", "1.0.0", instructions, "Sum a list of values") | |
| def make_factorial_iterative(n: int) -> VMProgram: | |
| """Build a program that computes n! iteratively.""" | |
| source = f""" | |
| PUSH {n} ; counter n | |
| PUSH 1 ; accumulator | |
| loop: | |
| SWAP ; acc, n | |
| DUP ; acc, n, n | |
| PUSH 0 | |
| EQ ; acc, n, (n==0) | |
| JNZ done ; if n==0 jump to done | |
| SWAP ; n, acc | |
| COPY 1 ; n, acc, n | |
| MUL ; n, acc*n | |
| SWAP ; acc*n, n | |
| PUSH 1 | |
| SUB ; acc*n, n-1 | |
| SWAP ; n-1, acc*n | |
| JMP loop | |
| done: | |
| POP ; remove counter | |
| HALT | |
| """ | |
| try: | |
| asm = VMAssembler() | |
| instructions = asm.assemble(source) | |
| return VMProgram(f"factorial_{n}", "1.0.0", instructions, | |
| f"Compute {n}!") | |
| except Exception: | |
| # Fallback: just push the result directly | |
| import math as _math | |
| result = _math.factorial(n) | |
| return VMProgram(f"factorial_{n}", "1.0.0", | |
| [VMInstruction(VMOpcode.PUSH, result), | |
| VMInstruction(VMOpcode.HALT)], | |
| f"Precomputed {n}!") | |
| def make_nand_truth_table() -> VMProgram: | |
| """Build a program that computes all 4 NAND combinations.""" | |
| instructions = [ | |
| # NAND(0,0) = 1 | |
| VMInstruction(VMOpcode.PUSH, 0), | |
| VMInstruction(VMOpcode.PUSH, 0), | |
| VMInstruction(VMOpcode.NAND), | |
| # NAND(0,1) = 1 | |
| VMInstruction(VMOpcode.PUSH, 0), | |
| VMInstruction(VMOpcode.PUSH, 1), | |
| VMInstruction(VMOpcode.NAND), | |
| # NAND(1,0) = 1 | |
| VMInstruction(VMOpcode.PUSH, 1), | |
| VMInstruction(VMOpcode.PUSH, 0), | |
| VMInstruction(VMOpcode.NAND), | |
| # NAND(1,1) = 0 | |
| VMInstruction(VMOpcode.PUSH, 1), | |
| VMInstruction(VMOpcode.PUSH, 1), | |
| VMInstruction(VMOpcode.NAND), | |
| # Commit truth table to WORM | |
| VMInstruction(VMOpcode.COMMIT), | |
| VMInstruction(VMOpcode.HALT), | |
| ] | |
| return VMProgram("nand_truth_table", "1.0.0", instructions, | |
| "NAND truth table with WORM commit") | |
| if __name__ == "__main__": | |
| assert _self_test(), "Self-test failed" | |
| print("vm_executor.py: all self-tests passed") | |
| # Demo: sum program | |
| prog = make_sum_program([1, 2, 3, 4, 5]) | |
| result = prog.run() | |
| print(f"Sum [1..5] = {result}") | |
| # Demo: NAND truth table | |
| nand_prog = make_nand_truth_table() | |
| vm = nand_prog.build_vm() | |
| vm.run() | |
| stack = vm.get_stack() | |
| print(f"NAND truth table stack (bottom to top): {stack}") | |
| print(f"WORM commits: {vm.worm_log().count()}") | |
| # Demo: profiling | |
| prof_vm = ProfilingVM([ | |
| VMInstruction(VMOpcode.PUSH, 100), | |
| VMInstruction(VMOpcode.PUSH, 200), | |
| VMInstruction(VMOpcode.ADD), | |
| VMInstruction(VMOpcode.NAND), | |
| VMInstruction(VMOpcode.NOT), | |
| VMInstruction(VMOpcode.COMMIT), | |
| VMInstruction(VMOpcode.HALT), | |
| ]) | |
| prof_vm.run() | |
| print("\n" + prof_vm.profile().summary()) | |
| # Demo: benchmark | |
| bench = VMBenchmark() | |
| nop_result = bench.run_nop_loop(100) | |
| print(f"\nBenchmark NOP loop: {nop_result['ips']:.0f} instructions/sec") | |
| arith_result = bench.run_arithmetic(50) | |
| print(f"Benchmark arithmetic: {arith_result['steps']} steps, " | |
| f"result={arith_result['result']}") | |
| # Demo: assembler disassembly | |
| asm = VMAssembler() | |
| prog2 = [ | |
| VMInstruction(VMOpcode.PUSH, 42), | |
| VMInstruction(VMOpcode.PUSH, 58), | |
| VMInstruction(VMOpcode.ADD), | |
| VMInstruction(VMOpcode.COMMIT), | |
| VMInstruction(VMOpcode.HALT), | |
| ] | |
| print("\n" + asm.disassemble(prog2)) | |