Advanced Concepts
Aura is designed for high-performance systems programming with modern abstractions. This section dives deep into its internal mechanisms, from memory management to the compiler pipeline.
Memory Management & GC​
Aura employs a Generational Garbage Collector designed for high throughput and low latency. It automates memory safety while providing performance characteristics suitable for systems-level applications.
Generational Heap Structure​
The heap is divided into two primary generations:
- Young Generation (Nursery): Most objects are initially allocated here using a fast bump-pointer allocator. It consists of a "from-space" and a "to-space" (each 2 MiB by default).
- Old Generation: Objects that survive multiple collection cycles in the young generation are promoted to the old generation (8 MiB by default).
Collection Strategy​
- Minor GC (Scavenge): Uses Cheney's copying algorithm to move live objects from the young from-space to the to-space or promote them to the old generation. It is extremely fast and has minimal pause times.
- Major GC (Mark-Compact): Triggered when the old generation is full. It performs a mark-and-compact pass to reclaim space and reduce fragmentation.
- Write Barriers: Aura's compiler automatically inserts write barriers for pointer assignments to ensure the GC maintains a correct root set across generations.
Concurrency & Async​
Aura's concurrency model is built around Lightweight Tasks and a Work-Stealing Scheduler, drawing inspiration from modern runtimes like Go and Tokio.
The Work-Stealing Scheduler​
- Worker Threads: The runtime spawns a pool of worker threads (matching CPU cores).
- Local Deques: Each worker has its own double-ended task queue. Workers push and pop tasks from the back (LIFO) to maximize cache locality.
- Stealing: When a worker runs out of tasks, it attempts to "steal" tasks from the front (FIFO) of other workers' queues, ensuring fair load distribution across all cores.
Promises and Tasks​
async functions in Aura return Promises. These are non-blocking and are polled by the scheduler until completion. Tasks are the unit of execution that the scheduler manages, abstracting away raw OS threads.
Error Handling​
Aura treats errors as first-class citizens, avoiding the overhead and complexity of traditional exceptions.
- Explicit Returns: Functions that can fail return multiple values (usually the result and an error object), similar to Go's pattern.
- Panic Mechanism: For unrecoverable errors, Aura provides a
panicmechanism that halts the current task and provides a detailed stack trace for debugging. - Zero-Cost Abstractions: The error handling paths are optimized to ensure that "sunny day" execution paths incur zero performance overhead.
Foreign Function Interface (FFI)​
Aura provides a robust FFI for interoperability with C and system-level libraries.
- C Linkage: Aura can call functions exported from C libraries by declaring them with the
externkeyword. - Memory Safety: While FFI calls are inherently "unsafe," Aura provides wrappers to ensure that GC-managed objects can be passed to C safely without being moved or reclaimed during the call.
- Static Linking: The Aura compiler statically links the runtime and any declared FFI dependencies into a single, self-contained binary.
Compiler Architecture (IR & Codegen)​
The Aura compiler follows a modern multi-pass design, culminating in a custom backend for AArch64.
SSA-based Intermediate Representation (IR)​
Aura uses an internal Static Single Assignment (SSA) IR. This format enables powerful optimization passes, including:
- Dead code elimination
- Constant folding
- Register pressure reduction
The IR includes high-level instructions for memory allocation (alloc), virtual method calls (call_virtual), and GC synchronization (write_barrier).
AArch64 Codegen​
The primary backend targets aarch64-apple-darwin (Apple Silicon). It features:
- Custom Register Allocator: Optimizes the use of the 31 general-purpose registers (
x0-x30) and 32 floating-point registers (d0-d31). - Direct Machine Code Emission: Generates highly optimized assembly directly from the IR, avoiding generic intermediate tools where possible.
- Static Runtime Integration: The language runtime (including the GC and scheduler) is written in C and Assembly and is statically embedded into every compiled Aura binary.
Advanced Type System​
Aura's type system combines the safety of static typing with the flexibility of modern type theory features.
Union Types​
Aura supports Union Types, allowing a variable to hold values of multiple different types. This is particularly useful for modelling optional data or alternative return paths without complex class hierarchies.
- Syntax:
let x: int | string = 10; - Type Narrowing: The compiler automatically narrows the type of a variable within conditional blocks if it can prove the specific type at runtime (e.g., after an
ischeck).
Generics​
Generics allow for writing reusable, type-safe code that works with any data type.
- Type Parameters: Functions and classes can be parameterized with types, e.g.,
class Box<T> { val: T }. - Compile-time Specialization: The Aura compiler uses monomorphization or type-erasure depending on the target backend to ensure that generic code remains highly efficient.
Language Intrinsics​
Intrinsics are special functions implemented directly by the compiler. They provide access to low-level CPU instructions or runtime internals that cannot be expressed purely in Aura syntax, such as:
- Atomic operations
- Direct memory access (in specific contexts)
- Performance-critical math functions