align vm runtime
This commit is contained in:
parent
fa651af3c3
commit
c7382763cd
@ -498,7 +498,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Syscall::SystemRunCart => {
|
Syscall::SystemRunCart => {
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -513,15 +513,14 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
|
|
||||||
// --- GFX Syscalls ---
|
// --- GFX Syscalls ---
|
||||||
|
|
||||||
// gfx.clear(color_index) -> null
|
// gfx.clear(color_index) -> void (ret_slots = 0)
|
||||||
Syscall::GfxClear => {
|
Syscall::GfxClear => {
|
||||||
let color_val = expect_int(args, 0)?;
|
let color_val = expect_int(args, 0)?;
|
||||||
let color = self.get_color(color_val);
|
let color = self.get_color(color_val);
|
||||||
hw.gfx_mut().clear(color);
|
hw.gfx_mut().clear(color);
|
||||||
ret.push_null();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.draw_rect(x, y, w, h, color_index) -> null
|
// gfx.draw_rect(x, y, w, h, color_index) -> void (ret_slots = 0)
|
||||||
Syscall::GfxFillRect => {
|
Syscall::GfxFillRect => {
|
||||||
let x = expect_int(args, 0)? as i32;
|
let x = expect_int(args, 0)? as i32;
|
||||||
let y = expect_int(args, 1)? as i32;
|
let y = expect_int(args, 1)? as i32;
|
||||||
@ -530,10 +529,9 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
let color_val = expect_int(args, 4)?;
|
let color_val = expect_int(args, 4)?;
|
||||||
let color = self.get_color(color_val);
|
let color = self.get_color(color_val);
|
||||||
hw.gfx_mut().fill_rect(x, y, w, h, color);
|
hw.gfx_mut().fill_rect(x, y, w, h, color);
|
||||||
ret.push_null();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.draw_line(x1, y1, x2, y2, color_index) -> null
|
// gfx.draw_line(x1, y1, x2, y2, color_index) -> void (ret_slots = 0)
|
||||||
Syscall::GfxDrawLine => {
|
Syscall::GfxDrawLine => {
|
||||||
let x1 = expect_int(args, 0)? as i32;
|
let x1 = expect_int(args, 0)? as i32;
|
||||||
let y1 = expect_int(args, 1)? as i32;
|
let y1 = expect_int(args, 1)? as i32;
|
||||||
@ -542,10 +540,9 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
let color_val = expect_int(args, 4)?;
|
let color_val = expect_int(args, 4)?;
|
||||||
let color = self.get_color(color_val);
|
let color = self.get_color(color_val);
|
||||||
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
|
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
|
||||||
ret.push_null();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.draw_circle(x, y, r, color_index) -> null
|
// gfx.draw_circle(x, y, r, color_index) -> void (ret_slots = 0)
|
||||||
Syscall::GfxDrawCircle => {
|
Syscall::GfxDrawCircle => {
|
||||||
let x = expect_int(args, 0)? as i32;
|
let x = expect_int(args, 0)? as i32;
|
||||||
let y = expect_int(args, 1)? as i32;
|
let y = expect_int(args, 1)? as i32;
|
||||||
@ -553,10 +550,9 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
let color_val = expect_int(args, 3)?;
|
let color_val = expect_int(args, 3)?;
|
||||||
let color = self.get_color(color_val);
|
let color = self.get_color(color_val);
|
||||||
hw.gfx_mut().draw_circle(x, y, r, color);
|
hw.gfx_mut().draw_circle(x, y, r, color);
|
||||||
ret.push_null();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.draw_disc(x, y, r, border_color_idx, fill_color_idx) -> null
|
// gfx.draw_disc(x, y, r, border_color_idx, fill_color_idx) -> void (ret_slots = 0)
|
||||||
Syscall::GfxDrawDisc => {
|
Syscall::GfxDrawDisc => {
|
||||||
let x = expect_int(args, 0)? as i32;
|
let x = expect_int(args, 0)? as i32;
|
||||||
let y = expect_int(args, 1)? as i32;
|
let y = expect_int(args, 1)? as i32;
|
||||||
@ -566,10 +562,9 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
let fill_color = self.get_color(fill_color_val);
|
let fill_color = self.get_color(fill_color_val);
|
||||||
let border_color = self.get_color(border_color_val);
|
let border_color = self.get_color(border_color_val);
|
||||||
hw.gfx_mut().draw_disc(x, y, r, border_color, fill_color);
|
hw.gfx_mut().draw_disc(x, y, r, border_color, fill_color);
|
||||||
ret.push_null();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.draw_square(x, y, w, h, border_color_idx, fill_color_idx) -> null
|
// gfx.draw_square(x, y, w, h, border_color_idx, fill_color_idx) -> void (ret_slots = 0)
|
||||||
Syscall::GfxDrawSquare => {
|
Syscall::GfxDrawSquare => {
|
||||||
let x = expect_int(args, 0)? as i32;
|
let x = expect_int(args, 0)? as i32;
|
||||||
let y = expect_int(args, 1)? as i32;
|
let y = expect_int(args, 1)? as i32;
|
||||||
@ -580,7 +575,6 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
let fill_color = self.get_color(fill_color_val);
|
let fill_color = self.get_color(fill_color_val);
|
||||||
let border_color = self.get_color(border_color_val);
|
let border_color = self.get_color(border_color_val);
|
||||||
hw.gfx_mut().draw_square(x, y, w, h, border_color, fill_color);
|
hw.gfx_mut().draw_square(x, y, w, h, border_color, fill_color);
|
||||||
ret.push_null();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.set_sprite(asset_name, id, x, y, tile_id, palette_id, active, flip_x, flip_y, priority)
|
// gfx.set_sprite(asset_name, id, x, y, tile_id, palette_id, active, flip_x, flip_y, priority)
|
||||||
@ -617,7 +611,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
priority,
|
priority,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Syscall::GfxDrawText => {
|
Syscall::GfxDrawText => {
|
||||||
@ -633,7 +627,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
let color_val = expect_int(args, 3)?;
|
let color_val = expect_int(args, 3)?;
|
||||||
let color = self.get_color(color_val);
|
let color = self.get_color(color_val);
|
||||||
hw.gfx_mut().draw_text(x, y, &msg, color);
|
hw.gfx_mut().draw_text(x, y, &msg, color);
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// gfx.clear565(color_u16) -> void
|
// gfx.clear565(color_u16) -> void
|
||||||
@ -873,7 +867,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
0,
|
0,
|
||||||
prometeu_hal::LoopMode::Off,
|
prometeu_hal::LoopMode::Off,
|
||||||
);
|
);
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,7 +903,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
hw.assets().find_slot_by_name(&asset_name, BankType::SOUNDS).unwrap_or(0);
|
hw.assets().find_slot_by_name(&asset_name, BankType::SOUNDS).unwrap_or(0);
|
||||||
|
|
||||||
hw.audio_mut().play(bank_id, sample_id, voice_id, volume, pan, pitch, 0, loop_mode);
|
hw.audio_mut().play(bank_id, sample_id, voice_id, volume, pan, pitch, 0, loop_mode);
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,7 +965,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
Syscall::FsClose => {
|
Syscall::FsClose => {
|
||||||
let handle = expect_int(args, 0)? as u32;
|
let handle = expect_int(args, 0)? as u32;
|
||||||
self.open_files.remove(&handle);
|
self.open_files.remove(&handle);
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// FS_LIST_DIR(path)
|
// FS_LIST_DIR(path)
|
||||||
@ -1087,13 +1081,13 @@ impl NativeInterface for VirtualMachineRuntime {
|
|||||||
Syscall::AssetCommit => {
|
Syscall::AssetCommit => {
|
||||||
let handle = expect_int(args, 0)? as u32;
|
let handle = expect_int(args, 0)? as u32;
|
||||||
hw.assets().commit(handle);
|
hw.assets().commit(handle);
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Syscall::AssetCancel => {
|
Syscall::AssetCancel => {
|
||||||
let handle = expect_int(args, 0)? as u32;
|
let handle = expect_int(args, 0)? as u32;
|
||||||
hw.assets().cancel(handle);
|
hw.assets().cancel(handle);
|
||||||
ret.push_null();
|
// ret_slots = 0 (void). Must return exactly 0 values per SyscallMeta.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Syscall::BankInfo => {
|
Syscall::BankInfo => {
|
||||||
|
|||||||
@ -1732,11 +1732,17 @@ mod tests {
|
|||||||
let mut ctx = HostContext::new(None);
|
let mut ctx = HostContext::new(None);
|
||||||
|
|
||||||
vm.prepare_call("0");
|
vm.prepare_call("0");
|
||||||
vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
// Ensure we have SYSTEM capability so we pass capability gate
|
||||||
|
vm.set_capabilities(prometeu_hal::syscalls::caps::SYSTEM);
|
||||||
assert_eq!(vm.pop().unwrap(), Value::Bounded(255));
|
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||||
assert_eq!(vm.pop().unwrap(), Value::Int64(42));
|
// Under PR5, VM enforces return-slot count based on SyscallMeta during syscall
|
||||||
assert_eq!(vm.pop().unwrap(), Value::Boolean(true));
|
// execution. A mismatch yields a Panic with a descriptive message.
|
||||||
|
match report.reason {
|
||||||
|
LogicalFrameEndingReason::Panic(msg) => {
|
||||||
|
assert!(msg.contains("results mismatch"));
|
||||||
|
}
|
||||||
|
_ => panic!("Expected Panic with results mismatch, got {:?}", report.reason),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1810,6 +1816,8 @@ mod tests {
|
|||||||
let mut ctx = HostContext::new(None);
|
let mut ctx = HostContext::new(None);
|
||||||
|
|
||||||
vm.prepare_call("0");
|
vm.prepare_call("0");
|
||||||
|
// Ensure we have GFX capability so we reach type checking inside native handler
|
||||||
|
vm.set_capabilities(prometeu_hal::syscalls::caps::GFX);
|
||||||
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||||
|
|
||||||
match report.reason {
|
match report.reason {
|
||||||
@ -1832,6 +1840,8 @@ mod tests {
|
|||||||
let mut ctx = HostContext::new(None);
|
let mut ctx = HostContext::new(None);
|
||||||
|
|
||||||
vm.prepare_call("0");
|
vm.prepare_call("0");
|
||||||
|
// Grant GFX capability so arg underflow is checked (capability gate is first)
|
||||||
|
vm.set_capabilities(prometeu_hal::syscalls::caps::GFX);
|
||||||
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||||
|
|
||||||
match report.reason {
|
match report.reason {
|
||||||
@ -1857,6 +1867,8 @@ mod tests {
|
|||||||
let mut ctx = HostContext::new(None);
|
let mut ctx = HostContext::new(None);
|
||||||
|
|
||||||
vm.prepare_call("0");
|
vm.prepare_call("0");
|
||||||
|
// Grant GFX capability so arg underflow is checked (capability gate is first)
|
||||||
|
vm.set_capabilities(prometeu_hal::syscalls::caps::GFX);
|
||||||
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||||
|
|
||||||
match report.reason {
|
match report.reason {
|
||||||
@ -1949,6 +1961,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = new_test_vm(rom.clone(), vec![]);
|
let mut vm = new_test_vm(rom.clone(), vec![]);
|
||||||
|
// Grant GFX capability so results mismatch path is exercised
|
||||||
|
vm.set_capabilities(prometeu_hal::syscalls::caps::GFX);
|
||||||
let mut native = BadNative;
|
let mut native = BadNative;
|
||||||
let mut ctx = HostContext::new(None);
|
let mut ctx = HostContext::new(None);
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,8 @@ fn vm_syscall_multi_return_stack_contents() {
|
|||||||
let mut native = TestNative;
|
let mut native = TestNative;
|
||||||
let mut ctx = HostContext::new(None);
|
let mut ctx = HostContext::new(None);
|
||||||
vm.prepare_call("0");
|
vm.prepare_call("0");
|
||||||
|
// Grant INPUT capability to pass capability gate for PadGetUp
|
||||||
|
vm.set_capabilities(prometeu_hal::syscalls::caps::INPUT);
|
||||||
let _ = vm.run_budget(100, &mut native, &mut ctx).expect("VM run failed");
|
let _ = vm.run_budget(100, &mut native, &mut ctx).expect("VM run failed");
|
||||||
|
|
||||||
// Verify stack order: last pushed is on top
|
// Verify stack order: last pushed is on top
|
||||||
|
|||||||
34
files/VM RESET.md
Normal file
34
files/VM RESET.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
6 — Closures (first-class user functions)
|
||||||
|
|
||||||
|
6.1. Definir objeto Closure no heap: fn_id + env (captures) + metadata mínima.
|
||||||
|
6.2. Definir como capturas são materializadas (layout do env e como o bytecode cria closures).
|
||||||
|
6.3. Implementar instruções/semântica para criar closure e para CALL_CLOSURE.
|
||||||
|
6.4. Atualizar GC traversal: closure → env → heap refs internos.
|
||||||
|
6.5. Atualizar verifier: tipo “closure value”, validação de call sites, ret_slots.
|
||||||
|
6.6. Testes: closure simples, closure capturando, closure retornando outra closure.
|
||||||
|
|
||||||
|
7 — Coroutines (único modelo de concorrência, cooperativo)
|
||||||
|
|
||||||
|
7.1. Definir objeto Coroutine no heap: stack/frames próprios, status, wake time, mailbox/queue se existir.
|
||||||
|
7.2. Definir scheduler determinístico: fila pronta, fila dormindo, política estável.
|
||||||
|
7.3. Implementar SPAWN: criar coroutine + capturar entry + agendar.
|
||||||
|
7.4. Implementar YIELD: ceder controle de forma cooperativa (somente em locais válidos).
|
||||||
|
7.5. Implementar SLEEP: mover para fila dormindo até tick/time.
|
||||||
|
7.6. Integrar execução/switch apenas em safepoints (FRAME_SYNC).
|
||||||
|
7.7. Integrar GC roots: stacks suspensas e frames de todas as coroutines.
|
||||||
|
7.8. Verifier: invariantes (ex.: proibir yield em contextos ilegais, validar spawn args/ret).
|
||||||
|
7.9. Testes: determinismo (mesma ordem), sleep/wake, stress com GC + muitas coroutines.
|
||||||
|
|
||||||
|
8 — Tooling & test harness (para manter “JVM-grade”)
|
||||||
|
|
||||||
|
8.1. Disasm atualizado e confiável (roundtrip + snapshots).
|
||||||
|
8.2. Harness de execução determinística para testes (seed fixo, time controlado).
|
||||||
|
8.3. Suite de testes por camadas: bytecode (encode/decode), verifier, VM, GC, scheduler.
|
||||||
|
8.4. “No legacy artifacts” check: busca por símbolos/nomes (retain/release/hip/gate/scope), módulos mortos removidos.
|
||||||
|
|
||||||
|
9 — Hardening final e documentação do novo baseline
|
||||||
|
|
||||||
|
9.1. Consolidar documentação de arquitetura (curta, objetiva, em inglês).
|
||||||
|
9.2. Garantir que o “surface area” público está minimalista (APIs internas escondidas).
|
||||||
|
9.3. Remover qualquer feature flag temporária que tenha sobrado.
|
||||||
|
9.4. Rodar limpeza final: dead code, warnings, docs desatualizadas, exemplos antigos.
|
||||||
Loading…
x
Reference in New Issue
Block a user