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>
6.7 KiB
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.rsmanages a pool ofVec<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 anyusizevalue - Error:
VmError::InstructionLimitExceededwhen 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):
#[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_checkflag enables recursion detection
Performance Priorities
Optimization focus areas in src/rvm/vm/:
- Instruction dispatch — tight loop, minimal branch overhead
- Register window pooling — predictable allocation, zero unnecessary allocs
- Rule caching — avoid redundant evaluation
- Virtual document lookup caching — avoid redundant path navigation
- Comprehension building — efficient collection construction
Profile with benches/ (Criterion) before optimizing.