Files
regorus/docs/knowledge/rvm-architecture.md
copilot-swe-agent[bot] 524aab5528 Add knowledge docs, agent definitions, and skill files
Add comprehensive documentation and GitHub Copilot configuration:

- docs/knowledge/: 17 deep-dive knowledge files covering value semantics,
  RVM architecture, builtins, FFI boundary, feature composition, error
  handling migration, policy evaluation security, Rego semantics,
  interpreter/compiler architecture, Azure Policy/RBAC, engine API,
  time builtins, language extension guide, tooling architecture,
  causality/partial eval, Rego compiler, Azure Policy aliases, and
  telemetry/diagnostics

- .github/agents/: 16 role-specific AI agent definitions (red-teamer,
  semantics-expert, architect, performance-engineer, test-engineer,
  verification-engineer, security-auditor, reliability-engineer,
  support-engineer, ci-engineer, refactorer, api-steward, program-manager,
  demo-engineer, dx-engineer, tech-lead)

- .github/skills/: 6 workflow skill definitions (thorough-review,
  design-alternatives, add-builtin, opa-conformance, security-review,
  verification)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-04-25 21:20:10 +00:00

201 lines
6.7 KiB
Markdown

<!-- Copyright (c) Microsoft Corporation. All rights reserved. -->
<!-- Licensed under the MIT License. -->
# Knowledge: RVM Architecture
Deep knowledge about the Rego Virtual Machine. Read this before modifying
anything in `src/rvm/`. Also see `docs/rvm/architecture.md`,
`docs/rvm/instruction-set.md`, and `docs/rvm/vm-runtime.md`.
## Overview
The RVM compiles Rego policies to register-based bytecode with fixed-width
32-bit instructions, then executes them in a virtual machine:
```
Policy source → Lexer → Parser → AST → Compiler → Program (bytecode) → VM → Value
```
This is the **strategic execution path** — new optimization and feature work
focuses on the RVM, not the tree-walking interpreter.
## Directory Structure
```
src/rvm/
instructions/ Instruction definitions (fixed-width 32-bit opcodes)
program/
core.rs Program struct — instructions, literals, entry points, rule info
serialization/ Binary and JSON format implementations
recompile.rs Recompilation from partial programs
vm/
machine.rs RegoVM — registers, stacks, execution state
execution.rs Run-to-completion and suspendable execution loops
dispatch.rs Instruction dispatch
loops.rs Loop iteration (Any, Every, ForEach modes)
comprehension.rs Set/array/object comprehension builders
rules.rs Rule evaluation, caching, call stacks
virtual_data.rs Virtual document lookup and caching
state.rs Register window pooling and state management
errors.rs VmError — strongly typed VM errors
tests/ RVM-specific test suites
```
## Two Execution Modes
### Run-to-Completion
The VM executes instructions sequentially until the program completes or
errors. No suspension. This is the **fast path** for synchronous policy
evaluation. Most production use cases.
### Suspendable
The VM can suspend mid-execution and be resumed later:
| Reason | Use case |
|--------|----------|
| **HostAwait** | Program needs external data from the host |
| **Breakpoint** | Debugging support |
| **SingleStep** | Instruction-by-instruction execution |
The host calls `vm.resume(value)` to continue after suspension. The VM
preserves its entire execution state across suspend/resume cycles.
**Important:** `SuspendReason` variants that appear in run-to-completion mode
trigger `VmError::UnsupportedSuspendInRunToCompletion`.
## Frame Stack
The suspendable mode uses an explicit frame stack (`execution_stack`) with
frame kinds:
| Frame Kind | Purpose |
|------------|---------|
| **Main** | Top-level program execution |
| **Rule** | Rule body evaluation |
| **Loop** | Collection iteration (Any, Every, ForEach) |
| **Comprehension** | Set/array/object comprehension building |
Each frame tracks its own:
- Program counter (PC)
- Register window (base + count)
- Saved caller state (for restoration on frame pop)
Frames are pushed on entry and popped on completion. The frame stack is the
mechanism that makes suspension possible — the entire execution state is
captured in the stack.
## Register Window Pooling
The VM reuses register vectors to minimize allocation:
- **Pool**: `state.rs` manages a pool of `Vec<Value>` vectors
- **Window**: Each frame gets a register window (base offset + count)
- **Reuse**: When a frame pops, its register vector returns to the pool
- **Predictable**: Allocation pattern is bounded and deterministic
**Invariant:** New VM features MUST participate in register window pooling.
Do not allocate fresh Vecs for register storage.
## Instruction Budget
The VM enforces a configurable instruction limit to prevent unbounded execution:
- **Default**: 25,000 instructions (`machine.rs`)
- **Enforcement**: Checked in the execution loop (`execution.rs`)
- **Configurable**: `set_max_instructions(limit)` allows any `usize` value
- **Error**: `VmError::InstructionLimitExceeded` when exceeded
This is the primary defense against denial-of-service via crafted policies.
All new execution paths must respect this budget — do not add loops or
recursion that bypass the instruction counter.
## Program Serialization
Compiled programs can be serialized for distribution and cached execution.
### Binary Format (Primary)
Compact, fast deserialization. Used for production distribution of pre-compiled
policies. Implemented via the `postcard` crate.
### JSON Format (Debugging)
Human-readable. Useful for debugging, tooling, and inspection.
### Artifact Structure
The program has two sections:
**Stable section** (always serializable):
- Source files, entry points, metadata
- Rule information, builtin references
- Sufficient to recompile the execution section
**Execution section** (version-sensitive):
- Instructions, literals, parameter tables
- May fail to deserialize on format version mismatch
**Recompilation fallback**: If the execution section can't be deserialized
(e.g., after a regorus version upgrade), it can be recompiled from the stable
section. This is handled by `recompile.rs`.
### Program Limits
`validate_limits()` in `program/core.rs` enforces hard bounds:
| Resource | Limit |
|----------|-------|
| Instructions | 65,535 |
| Literals | 65,535 |
| Rules | 4,000 |
| Entry points | 1,000 |
| Source files | 256 |
| Builtins | 512 |
| Path depth | 32 |
These limits prevent adversarial programs from consuming excessive resources.
## VmError Pattern
The RVM uses strongly typed errors (`src/rvm/vm/errors.rs`):
```rust
#[derive(Error, Debug, Clone, PartialEq)]
pub enum VmError {
#[error("Execution stopped: exceeded maximum instruction limit of {limit} ...")]
InstructionLimitExceeded { limit: usize, executed: usize, pc: usize },
// ... 30+ variants
}
```
Every error variant includes `pc` (program counter) for debugging. This is the
reference pattern for strongly typed errors in regorus — new subsystems should
follow this design.
## Rule Caching
The VM caches rule evaluation results to avoid redundant computation:
- Rules are identified by index
- Cache is checked before evaluation
- Cache size must match rule info count (`VmError::RuleCacheSizeMismatch`)
## Virtual Document Lookup
Virtual documents (rules-as-data) are resolved through `virtual_data.rs`:
- Paths are navigated through the rule tree
- Results are cached per-evaluation
- `needs_runtime_recursion_check` flag enables recursion detection
## Performance Priorities
Optimization focus areas in `src/rvm/vm/`:
1. **Instruction dispatch** — tight loop, minimal branch overhead
2. **Register window pooling** — predictable allocation, zero unnecessary allocs
3. **Rule caching** — avoid redundant evaluation
4. **Virtual document lookup caching** — avoid redundant path navigation
5. **Comprehension building** — efficient collection construction
Profile with `benches/` (Criterion) before optimizing.