Bliss Memory Model – Design Summary
This document summarizes the memory model and runtime architecture designed for the Bliss language.
The goal is to achieve:
- Strong memory safety (no undefined behavior)
- High performance (comparable to C/Rust on hot paths)
- Explicit control over dynamic memory
- Clear language semantics
- Predictable runtime behavior
1. Core Philosophy
Memory safety is not about preventing all mistakes.
It is about:
Converting undefined behavior into deterministic runtime failure.
Invalid memory operations must:
- be detected
- produce precise errors
- never corrupt program state
- never continue execution silently
2. Fundamental Axioms
Axiom 1 – Primitives are copied
All primitive values are passed by value.
No aliasing. No lifetime issues.
Axiom 2 – Primitives are not objects
Primitives:
- do not use
new - do not support
cloneordrop - are never heap allocated
- have no identity
Axiom 3 – Objects are reference-based
Objects:
- are passed by reference
- require explicit
new clonealways means deep copy- have identity
3. Dual-Mode Memory Model
Bliss uses two distinct memory worlds.
A. Value / Struct Mode (Default)
Example:
Data x = init Data();
Properties:
- Stack or register allocated
- Copy-by-value
- No heap
- No identity
- No vtables
- No metadata
- No
drop,clone, or references - Fully statically analyzed
- Zero runtime overhead
Equivalent to:
- C structs
- Rust stack values
- Swift structs
B. Object / Self-Managed Mode (Explicit)
Example:
Data x = new Data();
Properties:
- Heap allocated
- Has identity
- Uses handles (virtual pointers)
- Has metadata
- Optional vtable
- Supports mutation
- Supports shared references
- Supports
dropandclone - Runtime memory safety checks
Used only when semantics require:
- dynamic lifetime
- polymorphism
- shared ownership
- cyclic graphs
- escaping closures
- containers
4. Static Analysis Boundary
The compiler attempts to prove value-mode safety.
If it cannot, compilation fails:
[Compiler::Error]
Static memory safety analysis cannot safely track variable "counter".
Use `new` to create a self-managed object.
This makes dynamic memory:
- explicit
- intentional
- auditable
- predictable
5. Virtual Pointers (Handles)
Objects are not accessed via raw addresses.
Instead:
Handle = { object_id, generation }
Runtime maintains:
object_id → { data_ptr, generation, type_id, alive }
On access:
- generation must match
- object must be alive
- otherwise → runtime trap
This guarantees:
- use-after-free detection
- double-free detection
- pointer reuse safety
- type safety
- sandboxing
6. VTables (Selective)
VTables are used only for self-managed objects and only when:
- polymorphism
- interfaces
- dynamic dispatch
Struct/value types never use vtables.
Method dispatch:
type_id → vtable → function
7. Instruction Set Split
Value instructions
load32
store32
copy64
memcpy_struct
add
mul
No safety checks.
Object instructions
newobj
dropobj
loadfld
storefld
callvirt
cloneobj
Always validated through the object table.
8. Allocation Model
new Object() performs:
- Allocate object data
- Allocate object_id slot
- Initialize metadata
- Return handle
Objects do not store headers inline.
Metadata is centralized for cache efficiency.
9. Memory Errors
Memory violations are fatal runtime traps, not catchable exceptions:
- use-after-free
- double free
- invalid handle
- type mismatch
- invalid object access
These errors:
- halt execution
- report allocation site
- report free site
- report access site
10. Performance Characteristics
Value mode:
- Same performance as C/Rust
- Zero runtime overhead
- Cache-friendly
- Vectorizable
Object mode:
- Handle lookup
- Generation check
- Optional vtable call
No:
- garbage collection
- tracing
- write barriers
- heap scanning
- stop-the-world pauses
On average:
Faster than GC languages
Comparable to Rust
Predictable latency
11. Safety Guarantees
| Property | Value Mode | Object Mode |
|---|---|---|
| Use-after-free | Impossible | Detected |
| Double free | Impossible | Detected |
| Aliasing bugs | Impossible | Controlled |
| Pointer forgery | Impossible | Impossible |
| Silent corruption | Impossible | Impossible |
12. Design Outcome
Bliss achieves:
- Compile-time safety for simple code
- Runtime safety for complex code
- Explicit performance control
- Clear semantics
- No garbage collector
- No borrow checker
- No undefined behavior
13. One-sentence Summary
Bliss is a language where:
Memory is safe by proof for values, safe by validation for objects, and unsafe code simply cannot execute silently.
End of document.