vixen 0.0.0

Reserve for the Vixen VM
Documentation
use std::collections::VecDeque;

// Flat, cache-friendly instruction format
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
enum Opcode {
    LoadConst = 0x01,
    Add = 0x02,
    Print = 0x03,
    Spawn = 0x04,
    Yield = 0x05,
    Halt = 0x06,
    Jump = 0x07,
    JumpIfZero = 0x08,
}

// Compact instruction: 1 byte opcode + 3 operands + 4-byte immediate
// Total: 8 bytes per instruction (cache-friendly)
#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct Instruction {
    opcode: u8,
    dest: u8,
    src1: u8,
    src2: u8,
    immediate: i32, // For constants, jump targets, etc.
}

impl Instruction {
    #[inline(always)]
    fn load_const(dest: u8, value: i32) -> Self {
        Self {
            opcode: Opcode::LoadConst as u8,
            dest,
            src1: 0,
            src2: 0,
            immediate: value,
        }
    }

    #[inline(always)]
    fn add(dest: u8, src1: u8, src2: u8) -> Self {
        Self {
            opcode: Opcode::Add as u8,
            dest,
            src1,
            src2,
            immediate: 0,
        }
    }

    #[inline(always)]
    fn print(src: u8) -> Self {
        Self {
            opcode: Opcode::Print as u8,
            dest: src,
            src1: 0,
            src2: 0,
            immediate: 0,
        }
    }

    #[inline(always)]
    fn spawn(entry_point: usize) -> Self {
        Self {
            opcode: Opcode::Spawn as u8,
            dest: 0,
            src1: 0,
            src2: 0,
            immediate: entry_point as i32,
        }
    }

    #[inline(always)]
    fn yield_fiber() -> Self {
        Self {
            opcode: Opcode::Yield as u8,
            dest: 0,
            src1: 0,
            src2: 0,
            immediate: 0,
        }
    }

    #[inline(always)]
    fn halt() -> Self {
        Self {
            opcode: Opcode::Halt as u8,
            dest: 0,
            src1: 0,
            src2: 0,
            immediate: 0,
        }
    }

    #[inline(always)]
    fn jump(target: usize) -> Self {
        Self {
            opcode: Opcode::Jump as u8,
            dest: 0,
            src1: 0,
            src2: 0,
            immediate: target as i32,
        }
    }

    #[inline(always)]
    fn jump_if_zero(src: u8, target: usize) -> Self {
        Self {
            opcode: Opcode::JumpIfZero as u8,
            dest: src,
            src1: 0,
            src2: 0,
            immediate: target as i32,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum FiberStatus {
    Running,
    Yielded,
    Done,
}

// Smaller register set - 16 registers fits in a single cache line (64 bytes)
#[derive(Debug, Clone)]
struct Fiber {
    id: u16,
    ip: usize,
    registers: [i32; 16], // Reduced from 256 to 16
    status: FiberStatus,
}

impl Fiber {
    #[inline]
    fn new(id: u16, entry_point: usize) -> Self {
        Fiber {
            id,
            ip: entry_point,
            registers: [0; 16],
            status: FiberStatus::Running,
        }
    }
}

struct VM {
    fibers: Vec<Fiber>,
    ready_queue: VecDeque<usize>, // Store indices, not IDs
    current_fiber_index: usize,
    next_fiber_id: u16,
}

impl VM {
    fn new() -> Self {
        let main_fiber = Fiber::new(0, 0);
        let mut ready_queue = VecDeque::with_capacity(64); // Pre-allocate
        ready_queue.push_back(0); // Main fiber at index 0

        VM {
            fibers: vec![main_fiber],
            ready_queue,
            current_fiber_index: 0,
            next_fiber_id: 1,
        }
    }

    #[inline(always)]
    fn current_fiber(&self) -> &Fiber {
        // SAFETY: current_fiber_index is always valid during execution
        unsafe { self.fibers.get_unchecked(self.current_fiber_index) }
    }

    #[inline(always)]
    fn current_fiber_mut(&mut self) -> &mut Fiber {
        // SAFETY: current_fiber_index is always valid during execution
        unsafe { self.fibers.get_unchecked_mut(self.current_fiber_index) }
    }

    #[inline]
    fn spawn_fiber(&mut self, entry_point: usize) -> usize {
        let fiber_id = self.next_fiber_id;
        self.next_fiber_id += 1;

        let fiber = Fiber::new(fiber_id, entry_point);
        self.fibers.push(fiber);
        let fiber_index = self.fibers.len() - 1;

        self.ready_queue.push_back(fiber_index);
        fiber_index
    }

    #[inline]
    fn switch_fiber(&mut self) -> bool {
        while let Some(next_index) = self.ready_queue.pop_front() {
            // SAFETY: We only put valid indices in the queue
            let fiber = unsafe { self.fibers.get_unchecked(next_index) };

            if fiber.status == FiberStatus::Done {
                continue; // Skip done fibers
            }

            self.current_fiber_index = next_index;
            return true;
        }

        false // No more fibers to run
    }

    #[inline]
    fn yield_current(&mut self) {
        self.current_fiber_mut().status = FiberStatus::Yielded;
        self.ready_queue.push_back(self.current_fiber_index);
    }

    // Optimized dispatch with direct function calls
    #[inline(always)]
    fn execute_load_const(&mut self, dest: u8, value: i32) {
        let fiber = self.current_fiber_mut();
        fiber.registers[dest as usize] = value;
        fiber.ip += 1;
    }

    #[inline(always)]
    fn execute_add(&mut self, dest: u8, src1: u8, src2: u8) {
        let fiber = self.current_fiber_mut();
        let a = fiber.registers[src1 as usize];
        let b = fiber.registers[src2 as usize];
        fiber.registers[dest as usize] = a.wrapping_add(b);
        fiber.ip += 1;
    }

    #[inline(always)]
    fn execute_print(&mut self, src: u8) {
        let fiber = self.current_fiber();
        let val = fiber.registers[src as usize];
        let fiber_id = fiber.id;
        println!("[Fiber {fiber_id}] {val}");

        self.current_fiber_mut().ip += 1;
    }

    #[inline(always)]
    fn execute_spawn(&mut self, entry_point: usize) {
        let fiber_id = self.current_fiber().id;
        let new_index = self.spawn_fiber(entry_point);
        let new_fiber_id = self.fibers[new_index].id;
        println!("[Fiber {fiber_id}] Spawned fiber {new_fiber_id}");

        self.current_fiber_mut().ip += 1;
    }

    #[inline(always)]
    fn execute_yield(&mut self) -> bool {
        self.current_fiber_mut().ip += 1;
        self.yield_current();
        self.switch_fiber()
    }

    #[inline(always)]
    fn execute_halt(&mut self) -> bool {
        let fiber = self.current_fiber_mut();
        println!("[Fiber {}] Halted", fiber.id);
        fiber.status = FiberStatus::Done;
        self.switch_fiber()
    }

    #[inline(always)]
    fn execute_jump(&mut self, target: usize) {
        self.current_fiber_mut().ip = target;
    }

    #[inline(always)]
    fn execute_jump_if_zero(&mut self, src: u8, target: usize) {
        let fiber = self.current_fiber_mut();
        let val = fiber.registers[src as usize];

        if val == 0 {
            fiber.ip = target;
        } else {
            fiber.ip += 1;
        }
    }

    // Hot path: tight, optimized instruction loop
    fn run(&mut self, code: &[Instruction]) {
        // Start execution
        if !self.switch_fiber() {
            return;
        }

        'main_loop: loop {
            let fiber = self.current_fiber();
            let ip = fiber.ip;

            // Bounds check once per iteration
            if ip >= code.len() {
                self.current_fiber_mut().status = FiberStatus::Done;
                if !self.switch_fiber() {
                    break 'main_loop;
                }
                continue;
            }

            // SAFETY: We just bounds-checked above
            let instr = unsafe { code.get_unchecked(ip) };

            // Optimized dispatch - compiler can optimize this better than a match
            match instr.opcode {
                0x01 => self.execute_load_const(instr.dest, instr.immediate),
                0x02 => self.execute_add(instr.dest, instr.src1, instr.src2),
                0x03 => self.execute_print(instr.dest),
                0x04 => self.execute_spawn(instr.immediate as usize),
                0x05 => {
                    if !self.execute_yield() {
                        break 'main_loop;
                    }
                }
                0x06 => {
                    if !self.execute_halt() {
                        break 'main_loop;
                    }
                }
                0x07 => self.execute_jump(instr.immediate as usize),
                0x08 => self.execute_jump_if_zero(instr.dest, instr.immediate as usize),
                _ => {
                    eprintln!("Unknown opcode: {:#x}", instr.opcode);
                    break 'main_loop;
                }
            }
        }
    }
}

fn main() {
    let program = vec![
        // Instruction 0-7: Main fiber
        Instruction::load_const(0, 100),
        Instruction::print(0),
        Instruction::spawn(8),
        Instruction::spawn(15),
        Instruction::load_const(1, 999),
        Instruction::print(1),
        Instruction::yield_fiber(),
        Instruction::halt(),
        // Instruction 8-14: Worker fiber 1
        Instruction::load_const(10, 1),
        Instruction::print(10),
        Instruction::yield_fiber(),
        Instruction::load_const(11, 2),
        Instruction::print(11),
        Instruction::yield_fiber(),
        Instruction::halt(),
        // Instruction 15-21: Worker fiber 2
        Instruction::load_const(10, 10),
        Instruction::print(10),
        Instruction::yield_fiber(),
        Instruction::load_const(11, 20),
        Instruction::print(11),
        Instruction::yield_fiber(),
        Instruction::halt(),
    ];

    println!("=== Starting Optimized VM ===\n");
    let mut vm = VM::new();
    vm.run(&program);
    println!("\n=== VM Execution Complete ===");
}