Resilient Backend Architecture
Overview
Resilient supports multiple execution backends for different use cases. This document defines the architecture contract, feature support matrix, and selection guidance for each backend.
| Backend | Purpose | Stability | Performance | Memory |
|---|---|---|---|---|
| Interpreter | Development, debugging, prototyping | Stable | Slow (1000x) | High |
| VM | Embedded systems, resource-constrained | Stable | Medium (10-100x) | Low |
| JIT | Production systems, performance-critical | Backend-Limited | Fast (1-5x native) | Medium |
| Verifier | Safety proofs, formal verification | Experimental | N/A (static) | N/A |
Backend: Interpreter
Architecture
The interpreter is a tree-walking evaluator that directly executes the AST:
Source Code → Parser → AST → Interpreter → Output
Characteristics:
- Direct AST traversal
- No compilation step
- Immediate feedback
- Full source-level debugging
Feature Support
| Feature | Status | Notes |
|---|---|---|
| Basic types (int, string, bool) | ✅ Stable | Full support |
| Functions | ✅ Stable | Recursion supported |
| Arrays | ✅ Stable | Dynamic sizing |
| Structs | ✅ Stable | Named fields |
| Pattern matching | ✅ Stable | Exhaustiveness checked |
| Generics | ✅ Stable | Monomorphization at interpret time |
| Effects | ⚠️ Backend-Limited | Parsed but not enforced |
| Memory tiers (Stack/Static/Heap/MMIO) | ✅ Stable | All supported |
| Concurrency | ❌ Not Supported | Single-threaded only |
| JIT inline hints | ❌ N/A | Not applicable |
| SMT verification | ❌ N/A | No static analysis |
Use Cases
- Development: Rapid prototyping without compile times
- Debugging: Step through code execution
- Testing: Quick validation of logic
- Education: Understanding language semantics
Conformance Rules
- Must accept all valid Stable-tier code
- Must produce identical results to other backends
- Memory safety violations must be runtime errors, not panics
- Diagnostics must match compiler error messages
Backend: VM
Architecture
The VM is a bytecode interpreter with ahead-of-time compilation:
Source Code → Parser → Type Check → Bytecode → VM → Output
Characteristics:
- Bytecode-based execution
- Pre-compilation pass
- Register-based VM (16 registers)
- Optimized for embedded targets
Instruction Set
Core instruction categories:
- Arithmetic:
add,sub,mul,div,mod - Logic:
and,or,not,cmp - Memory:
load,store,alloc,free - Control:
jump,branch,call,return - I/O:
read,write,mmio_read,mmio_write - Effects:
enter_effect,exit_effect(metadata, not enforced)
Feature Support
| Feature | Status | Notes |
|---|---|---|
| Basic types | ✅ Stable | Full support |
| Functions | ✅ Stable | Tail-call optimization |
| Arrays | ✅ Stable | Bounds checked |
| Structs | ✅ Stable | Stack layout optimized |
| Pattern matching | ✅ Stable | Compiled to jump tables |
| Generics | ✅ Stable | Monomorphization at compile time |
| Effects | ✅ Stable | Tracked in bytecode |
| Stack allocation | ✅ Stable | SRAM-based |
| Static allocation | ✅ Stable | Flash or ROM |
| Heap allocation | ⚠️ Backend-Limited | Requires allocator configuration |
| MMIO access | ✅ Stable | Hardware registers supported |
| Concurrency | ❌ Not Supported | No task scheduler |
| JIT compilation | ❌ N/A | Different backend |
| Verification | ❌ N/A | Different backend |
Target Platforms
- Cortex-M (ARM Embedded): thumbv7em-none-eabihf, thumbv6m-none-eabi
- RISC-V: riscv32imac-unknown-none-elf
- x86-64 (simulation): x86_64-unknown-linux-gnu (testing only)
Memory Model
| Tier | Strategy | Notes |
|---|---|---|
| Stack | SRAM base + offset | Known at link time |
| Static | Flash base (with BSS) | Zero-initialized |
| Heap | Allocator instance | Optional, configurable |
| MMIO | Hardware address | Volatile reads/writes |
Conformance Rules
- All Stable features must work identically across all target platforms
- Embedded targets must run with ≤ 64 KiB
.textsection (size budget) - Stack overflow must be detectable (guard pages where available)
- MMIO accesses must preserve volatile semantics
- No panics in no_std runtime; use
Resultinstead
Backend: JIT
Architecture
The JIT backend compiles bytecode to native machine code at load time:
Source Code → Parser → Type Check → Bytecode → JIT → Native Code → CPU → Output
Characteristics:
- Just-in-time compilation to native code
- Aggressive optimization passes
- Low latency execution
- Target-specific instruction selection
Optimization Passes
- Monomorphization: Specialize generics to concrete types
- Inlining: Inline small functions
- Dead code elimination: Remove unreachable code
- Constant folding: Evaluate constants at compile time
- Strength reduction: Replace expensive ops with cheaper ones
- Loop unrolling: Unroll hot loops (with heuristics)
- Peephole: Local instruction optimization
Feature Support
| Feature | Status | Notes |
|---|---|---|
| Basic types | ✅ Stable | Full support |
| Functions | ✅ Stable | Aggressive inlining |
| Arrays | ✅ Stable | Bounds check elimination |
| Structs | ✅ Stable | Field access optimized |
| Pattern matching | ✅ Stable | Jump table optimization |
| Generics | ✅ Stable | Full specialization |
| Effects | ✅ Stable | Affects optimization strategy |
| Stack allocation | ✅ Stable | Stack frame optimization |
| Static allocation | ✅ Stable | RIP-relative addressing |
| Heap allocation | ✅ Stable | Inline allocations |
| MMIO access | ⚠️ Backend-Limited | Platform-dependent |
| Concurrency | ⚠️ Backend-Limited | Work-stealing scheduler |
| Verification | ❌ N/A | Different backend |
Target Platforms
- x86-64: x86_64-unknown-linux-gnu, x86_64-pc-windows-msvc
- ARM64: aarch64-unknown-linux-gnu
- Embedded (future): Integration with embedded JIT framework
Performance Targets
- Startup: < 100ms for typical programs
- Runtime: Within 1.5x of hand-written C for compute-heavy workloads
- Memory: < 50 MB for typical embedded applications
Conformance Rules
- Must produce output identical to interpreter (within floating-point precision)
- Optimization passes must be semantics-preserving
- Effect tracking must be accurate (no dead effect code elimination)
- Must respect platform-specific MMIO constraints
- Stack allocation must not exceed platform limits
Backend: Verifier (Z3-based)
Architecture
The verifier uses SMT solvers for formal verification:
Source Code → Parser → Type Check → Constraints → Z3 Solver → Proof/Counterexample
Characteristics:
- Static analysis (no execution)
- SMT-LIB2 constraint generation
- Automated theorem proving
- Generates proofs or counterexamples
Verification Capabilities
| Capability | Status | Notes |
|---|---|---|
| Type safety | ✅ Stable | Leverages type system |
| Memory safety | ✅ Stable | Lifetime + bounds checking |
| Integer overflow | ✅ Stable | Signed/unsigned analysis |
| Deadlock detection | ⚠️ Experimental | Concurrency model incomplete |
| Liveness proofs | ⚠️ Experimental | Requires effect boundaries |
| Custom assertions | ⚠️ Backend-Limited | Requires Z3 integration |
Feature Support
| Feature | Status | Notes |
|---|---|---|
| Basic types | ✅ Stable | Bitvector logic |
| Integer ranges | ✅ Stable | SMT-LIB support |
| Arrays | ✅ Stable | Array theory |
| Structs | ✅ Stable | Flattened to fields |
| Functions | ⚠️ Backend-Limited | Requires unrolling |
| Recursion | ⚠️ Experimental | Bounded unrolling |
| Generics | ⚠️ Backend-Limited | Monomorphized then verified |
| Floating-point | ⚠️ Experimental | IEEE-754 theory (incomplete) |
| Concurrency | ❌ Not Supported | Sequential assumptions |
| Optimization | ❌ N/A | Static analysis only |
Usage Model
#[verify] // Request verification for this function
fn safe_add(x: int, y: int) -> int {
// Verifier will prove no overflow if constraints hold
return x + y;
}
#[verify(bound = "x <= 1000000")]
fn bounded_add(x: int, y: int) -> int {
return x + y;
}
Conformance Rules
- All assertions must be satisfiable within reasonable time (< 10s per function)
- Proofs must be reproducible (deterministic solver state)
- Counterexamples must be minimal and debuggable
- Must not claim to verify unverifiable code
Feature Matrix by Backend
| Feature | Interpreter | VM | JIT | Verifier |
|---|---|---|---|---|
| Tier: Stable | ✅ | ✅ | ✅ | ❌ |
| Tier: Backend-Limited | ⚠️ | ⚠️ | ⚠️ | ✅ |
| Tier: Experimental | ✅ | ✅ | ✅ | ✅ |
| Basic types | ✅ | ✅ | ✅ | ✅ |
| Functions | ✅ | ✅ | ✅ | ⚠️ |
| Generics | ✅ | ✅ | ✅ | ⚠️ |
| Structs | ✅ | ✅ | ✅ | ✅ |
| Pattern matching | ✅ | ✅ | ✅ | ⚠️ |
| Effects | ⚠️ | ✅ | ✅ | ⚠️ |
| Stack allocation | ✅ | ✅ | ✅ | ⚠️ |
| Static allocation | ✅ | ✅ | ✅ | ✅ |
| Heap allocation | ✅ | ⚠️ | ✅ | ⚠️ |
| MMIO access | ✅ | ✅ | ⚠️ | ❌ |
| Concurrency | ❌ | ❌ | ⚠️ | ❌ |
Backend Selection Guide
Choose Interpreter If:
- Developing: Tight debug loop
- Prototyping: Quick iteration
- Learning: Understanding semantics
- Testing: Validating correctness first
Choose VM If:
- Embedded systems: Size/resource constraints
- Production (non-critical): Balanced performance
- Cross-platform: Consistent behavior needed
- Deployment: Pre-compiled, deterministic
Choose JIT If:
- Performance-critical: Native-speed execution needed
- Server workloads: High throughput required
- Desktop apps: Low latency expected
- Optimization: Aggressive specialization beneficial
Choose Verifier If:
- Safety-critical: Formal proofs required
- Security: Exhaustive analysis needed
- Compliance: Certification demands
- Research: Exploring verification techniques
Implementation Rules
Backend Invariants
- Identical semantics: All backends produce identical results on Stable code
- Error consistency: Runtime errors have the same origin and message
- Determinism: No non-deterministic behavior (for reproducibility)
- Type safety: No type violations possible
- Memory safety: No use-after-free, double-free, or data races
Adding a New Backend
- Implement minimal feature set (basic types, functions, control flow)
- Pass interpreter conformance test suite
- Document feature support matrix
- Add platform-specific tests
- Graduate from Experimental to Backend-Limited
- Eventually graduate to Stable if replaces existing backend
Feature Availability Rules
| Tier | Must support on | Can selectively support | Cannot support |
|---|---|---|---|
| Stable | All backends | N/A | N/A |
| Backend-Limited | Specified backends | Explicitly documented | Non-specified backends |
| Experimental | At least one backend | Yes | Not required |
Platform-Specific Notes
Cortex-M (ARM Embedded)
- Constraint: Typically ≤ 256 KB Flash, ≤ 64 KB RAM
- Typical budget: 64 KB
.text, 8 KB stack, 8 KB static data - Optimization: Aggressive code size optimization (-Os)
- Features: Full MMIO support for STM32, nRF, LPC families
RISC-V
- Constraint: Typically ≤ 4 MB Flash, variable RAM
- Typical budget: 256 KB
.text, 16 KB stack, 64 KB static data - Optimization: RV32IMC ISA subset
- Features: Full MMIO support for RISC-V interrupt controller
x86-64 (Linux/Windows)
- Constraint: Modern systems (2+ GB RAM typical)
- Optimization: Aggressive optimization, parallelism possible
- Features: Full concurrency support, system calls available
- Note: Primarily for development/testing, not deployment
CI/CD Integration
Build Matrix
backends:
- interpreter
- vm
platforms: [thumbv7em-none-eabihf, riscv32imac-unknown-none-elf]
- jit
platforms: [x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu]
- verifier
features: [z3]
Test Requirements
| Backend | Minimum tests | Performance gate |
|---|---|---|
| Interpreter | 100+ integration tests | < 5s per test |
| VM | 100+ + 3 platform targets | < 100ms startup |
| JIT | 100+ + 2 platform targets | < 2s startup + perf < 1.5x native |
| Verifier | 50+ + solver timeouts | < 10s per verification |
References
- RES-3506: Define the backend architecture contract
- RES-3502: Design a real module and package system
- LANGUAGE.md: Feature tier classification framework
- MEMORY_MODEL.md: Memory safety model across tiers