This commit is contained in:
bQUARKz 2026-03-10 10:08:20 +00:00
parent 9ac48379ed
commit 8152269d5b
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 0 additions and 428 deletions

View File

@ -1,198 +0,0 @@
Mini Spec — Borrow/Mutate Views on a GC Heap (Prometeu)
This document defines an optional “Rust-flavored” access discipline for heap objects without using RC/HIP. It is compatible with a GC-based heap, first-class functions (closures), and deterministic coroutines.
Goals
Preserve the feel of borrow (shared read) and mutate (exclusive write).
Prevent common aliasing bugs in user code.
Keep the runtime simple and GC-friendly.
Avoid restrictions that would block closures/coroutines.
Non-goals
Not a full Rust borrow checker.
Not a memory management mechanism (GC owns lifetimes).
Not a general concurrency/locking system.
1. Concepts
1.1 Heap handle
A heap object is referenced by a handle. Handles can be stored, copied, captured, and returned freely (GC-managed).
1.2 Views
A view is a temporary capability derived from a handle:
BorrowView<T>: shared read-only view
MutView<T>: exclusive mutable view
Views are stack-only and lexically scoped.
2. Core Rules (Language Semantics)
2.1 Creating views
Views can be created only by dedicated constructs:
borrow(h) { ... } produces a BorrowView for the duration of the block
mutate(h) { ... } produces a MutView for the duration of the block
2.2 View locality
Views must never escape their lexical scope:
A view cannot be:
stored into heap objects
captured by closures
returned from functions
yielded across coroutine suspension points
stored into globals
(Think: “views are ephemeral; handles are persistent.”)
2.3 Access permissions
Within a view scope:
BorrowView permits reads only
MutView permits reads and writes
Outside a view scope:
direct field access is not permitted; you must open a view scope again.
2.4 Exclusivity
At any program point, for a given handle h:
Multiple BorrowView(h) may coexist.
Exactly one MutView(h) may exist, and it excludes all borrows.
This is enforced at compile time (required) and optionally at runtime in debug mode (see §5).
2.5 Re-entrancy
Within a mutate(h) scope:
nested borrow(h) is allowed (it is trivially compatible)
nested mutate(h) is disallowed
Within a borrow(h) scope:
nested mutate(h) is disallowed
3. Interaction with Closures and Coroutines
3.1 Closures
Closures may capture handles freely.
Closures must not capture views.
If code inside borrow/mutate creates a closure, it may capture the handle, but not the view.
3.2 Coroutines
Coroutines may store handles in their stacks/locals.
Views must not live across suspension:
A coroutine cannot yield while a view is active.
A coroutine cannot sleep while a view is active.
This rule guarantees that view lifetimes remain local and deterministic.
4. Compiler Requirements (Static Enforcement)
The compiler enforces this feature by tracking view lifetimes as lexical regions.
Minimum checks:
A view cannot be assigned to a variable with heap lifetime.
A view cannot appear in a closure capture set.
A view cannot be returned.
A view cannot be live at FRAME_SYNC, YIELD, SLEEP, or any safe-point boundary defined by the language.
Exclusivity rules per handle region (borrow vs mutate overlaps) must hold.
If a rule is violated: compile error (fatal).
5. Optional Runtime Checking (Debug Mode)
Runtime checking is optional and intended for debugging or untrusted bytecode scenarios.
5.1 Object header borrow-state
Each heap object may maintain:
readers: u16
writer: bool
Runtime actions:
entering borrow increments readers if no writer
leaving borrow decrements readers
entering mutate requires readers==0 and writer==false, then sets writer=true
leaving mutate sets writer=false
Violations trap with a specific diagnostic.
5.2 Build profiles
Release builds may omit this entirely (zero overhead).
Debug builds may enable it.
6. Lowering to Bytecode (Suggested)
This feature does not require dedicated opcodes in the minimal design.
Recommended lowering strategy:
borrow/mutate are compile-time constructs.
Field reads/writes lower to existing heap access opcodes (FIELD_GET/FIELD_SET or equivalent), but only permitted while a view is considered “active” by the compiler.
In debug-runtime-check mode, the compiler may insert explicit enter/exit markers (or syscalls) to enable runtime enforcement.
7. Rationale
GC removes the need for RC/HIP, but aliasing mistakes still exist. Views provide a clean and didactic discipline:
Handles: long-lived, capturable, GC-managed.
Views: short-lived, local, safe access windows.
This keeps the VM simple while enabling expressive language features (closures, coroutines) without lifetime headaches.
8. Summary
Borrow/Mutate are access disciplines, not memory management.
Views are stack-only and non-escapable.
Closures and coroutines freely use handles, but never views.
Enforcement is compile-time, with optional runtime checks in debug mode.

View File

@ -1,186 +0,0 @@
# PR-6 — PBX Declared Syscalls Section (Load-Time Resolution Integration)
## Briefing
Chapter 16 requires that cartridges declare required syscalls using canonical identities `(module, name, version)` and that these be resolved at load time before the VM begins execution.
Until now, resolution has existed only as an API (PR5.3.2). The PBX on-disk format currently does not carry declared syscalls, and the loader cannot enforce load-time resolution deterministically.
This PR introduces a minimal, production-grade PBX section for **declared syscalls only** and integrates it into the PBX load sequence.
**Scope note (important):**
* PBX contains **program + syscall metadata** only.
* Assets (`asset_table`, `preload`, etc.) are explicitly **out of scope** for this PR and will be handled later via `asset.pa`.
After this PR:
* `program.pbx` contains a `SYSC` (declared syscalls) section.
* The PBX loader parses `SYSC` and resolves identities at load time.
* Load fails deterministically if resolution fails.
* The VM continues to execute `SYSCALL <id>` only.
No backward compatibility. No fallback to external manifests in production.
---
## Target
1. Define a minimal PBX section for declared syscalls.
2. Extend the PBX parser/loader to read this section.
3. Integrate `resolve_program_syscalls()` into PBX load.
4. Enforce load-time failure on unknown or unauthorized syscalls.
5. Keep VM runtime strictly numeric.
---
## PBX Section Format (Authoritative for This PR)
Add a new PBX chunk:
* Chunk ID: `SYSC`
Binary layout:
```
u32 count
repeat count times:
u16 module_len
[module_len bytes UTF-8]
u16 name_len
[name_len bytes UTF-8]
u16 version
```
Rules:
* UTF-8 strings only.
* No string table in this PR (keep it minimal).
* This section is REQUIRED for PBX v0 after this PR.
* If absent → load error.
* Duplicate `(module,name,version)` entries → load error.
**Out of scope:** Any asset-related metadata. Do not add `ASSET_TABLE`, `PRELOAD`, or anything similar to PBX in this PR.
---
## Load Sequence (After PR-6)
1. Parse PBX header and TOC.
2. Parse `SYSC` section into `Vec<SyscallIdentity>`.
3. Call:
```rust
resolve_program_syscalls(&declared, vm.capabilities)
```
4. If resolution fails → abort load deterministically.
5. Store resolved syscalls inside VM (or a `LoadedProgram` struct).
6. Start VM execution.
No runtime name resolution allowed.
---
## Work Items
### 1) PBX Parser / Loader Extension
* Add support for `SYSC` chunk in the PBX parser/loader.
* Return `declared_syscalls: Vec<SyscallIdentity>` as part of `ProgramImage` (or equivalent).
* If `SYSC` is missing → return load error.
### 2) Load-Time Resolver Integration
* In the PBX load path:
* Parse declared syscalls.
* Resolve using `prometeu_hal::syscalls::resolve_program_syscalls`.
* Enforce capability checks at load time.
* If resolution fails → load fails (no runtime fallback).
* Do NOT modify VM execution core beyond storing the resolved mapping.
### 3) VM State Storage
* Add or finalize storage for resolved syscalls (if not already present).
* VM must NOT use canonical strings at runtime.
* VM runtime continues to execute only numeric IDs.
### 4) Error Handling
PBX load must fail deterministically if:
* Unknown `(module,name,version)`.
* Capability mismatch.
* Duplicate identities in `SYSC`.
* `SYSC` chunk is missing.
* Malformed `SYSC` payload (lengths/UTF-8).
Errors must be explicit and deterministic.
---
## Acceptance Checklist
* [ ] PBX format supports `SYSC` chunk.
* [ ] Loader parses declared syscalls from PBX.
* [ ] Resolver runs during PBX load (before VM execution).
* [ ] Load fails on unknown syscall.
* [ ] Load fails on capability violation.
* [ ] Load fails when `SYSC` chunk is missing.
* [ ] No runtime name resolution exists.
* [ ] `cargo test` passes.
---
## Tests
Add tests covering:
1. Valid PBX with one syscall identity → loads successfully.
2. PBX with unknown syscall identity → load error.
3. PBX with capability violation → load error.
4. PBX without `SYSC` section → load error.
5. PBX with duplicate identity entries → load error.
6. PBX with malformed `SYSC` payload (bad lengths/invalid UTF-8) → load error.
Tests must construct minimal synthetic PBX images in-memory.
Do NOT rely on external files.
---
## Junie Instructions
You MAY:
* Extend PBX parser/loader to support `SYSC`.
* Integrate the resolver into the PBX load path.
* Add deterministic tests for load-time resolution.
You MUST NOT:
* Add backward compatibility paths.
* Add fallback to JSON manifests.
* Add any asset-table or preload metadata to PBX.
* Change VM runtime dispatch logic.
* Modify syscall numeric IDs.
If PBX container format details (header/TOC/chunk reading) are unclear:
* STOP.
* Ask for clarification before inventing new unrelated chunk structures.
No assumptions beyond the `SYSC` layout defined above.
---
## Definition of Done
After this PR:
* Syscall resolution is fully load-time for PBX.
* PBX is authoritative for declared syscalls.
* VM executes only numeric syscalls.
* No legacy or dev fallback exists in the production load path.
* No asset responsibilities are added to PBX.

View File

View File

@ -1,44 +0,0 @@
Layered Test Suite Architecture (PR8.3)
Overview
- Tests are organized by runtime layer to isolate failures and clarify ownership of behavior.
- Location: `crates/dev/prometeu-layer-tests/tests/`
Layers and representative tests
1. Bytecode encode/decode
- `bytecode_encode_decode.rs` — roundtrip decoding for edge immediates and structure.
2. Verifier
- `verifier_closure_reject.rs` — rejects `CALL_CLOSURE` when TOS is not a closure.
- Rule: verifier tests never run the VM.
3. VM execution
- `vm_exec_valid.rs` — executes a tiny valid program; assumes verified input.
- Rule: VM tests do not depend on the verifier; they prepare ROM directly.
4. GC behavior
- `gc_collect_unreachable.rs` — unrooted closure is reclaimed; rooted one survives.
5. Scheduler behavior
- `scheduler_determinism.rs` — deterministic FIFO ordering for sametick wakeups.
Running the layered suite
- Run just the layered tests: `cargo test -p prometeu-layer-tests`
- Run the entire workspace: `cargo test`
Host debugger socket tests
- The host debugger integration tests in `crates/host/prometeu-host-desktop-winit/src/runner.rs` open localhost TCP ports and are marked `#[ignore]` in the default test flow.
- This keeps `cargo test --workspace --all-targets --all-features --no-fail-fast` green in restricted environments that forbid `TcpListener::bind`.
- Run the socket-dependent suite explicitly with `make test-debugger-socket` or `cargo test -p prometeu-host-desktop-winit --lib -- --ignored`.
- These tests must still run in at least one official environment that permits localhost bind/connect.
Separation of concerns
- No crosslayer assumptions in these tests.
- Verifier tests: no `VirtualMachine` execution.
- VM tests: assume preverified bytecode; interact via public VM APIs only.
- GC and Scheduler tests: exercise their public APIs directly, without booting the VM.
DRY helpers
- Shared utilities should live in `crates/dev/prometeu-test-support` when needed. The current minimal suite avoids duplication by using tiny local helpers.