- Larva
- Cómo funciona Larva
- Arquitectura
Esta página aún no está traducida al español. Leer la versión en inglés
Architecture
How Larva turns a source file into a running program - the pipeline, the forms a program takes on the way (HIR, IR, IL, machine code), and which part of Larva does what.
En esta página
This part of the book explains how Larva works inside. It is written for people who build a language on Larva, work on Larva itself, or want to know what happens between larva build and a running program. The other books say how to use the tools; these pages say how they are made.
Larva is a compiler platform. It owns everything a program needs except the language it is written in: a typed object model (Larva HIR), the lowering of that model to a low-level IR, an IL and a VM, native back ends (LLVM, a direct x86-64 one, WebAssembly), a native runtime with several garbage collectors, project files, a package manager and native bindings. A language is a language pack: a frontend that turns source text into HIR, and a view that turns HIR back into source text. Larva never parses a language itself.
The pipeline
hello.ant Program.ant … (source files of any installed language)
│ │
└────────┬───────────┘
▼
┌──────────────────────────┐ compile request (JSON) ┌───────────────────────────────┐
│ language pack (frontend) │ ◄───────────────────────── │ larva (Larva.Cli, SourceBuild)│
│ lexer, parser, binder │ ─────────────────────────► │ reads .queen, picks options │
└──────────────────────────┘ HIR assembly (.lva) └───────────────────────────────┘
│
▼ System.Core.dll, libraries (.dll = PE + .lva section),
┌──────────────────────────┐ bindings, dependencies with another GC (own domain)
│ HIR link (HirLinker) │ ◄───────────────────────────────────────────────
└──────────────────────────┘ one closed HIR assembly: the whole program
│
▼
┌──────────────────────────┐ classes become structs + vtables, generics get requirements,
│ lowering (HirLowerer) │ closures/iterators/async become objects and state machines,
└──────────────────────────┘ try/catch becomes unwind edges, imports become native calls
│ Larva IR module (in memory; a .lvo when written)
▼
┌──────────────────────────┐ borrow check (enforce / warn / off), type check,
│ IR checks (Compiler) │ region check, safepoints, bounds facts
└──────────────────────────┘
│
▼
┌──────────────────────────┐ modules joined, imports resolved, link-once code shared,
│ IR link (Linker) │ GC domains assigned, entry wrapper chosen
└──────────────────────────┘
│
┌─────────┼──────────────┬──────────────────┬─────────────────────┐
▼ ▼ ▼ ▼ ▼
LLVM x86-64 WebAssembly WebAssembly IL (.lvm)
(Larva. (Larva.X64) via LLVM own back end (IlLowering)
Llvm) │ (wasm-llvm) (Larva.Wasm) │
│ │ │ │ ▼
▼ ▼ ▼ ▼ the VM
object file + larva_rt app.wasm + app.js (larva_rt.js) + app.html (Larva.Runtime)
│
▼
system linker (MSVC link) → app.exe / lib.dll
Every arrow but the first and the last happens inside the larva process, in memory. larva build writes no intermediate file: the HIR, the IR module and the linked program never touch the disk unless a tool asks for them.
You can see the phases with --timings. Each name is one step of the picture:
larva build --timings -o hello.exe hello.ant
hello.exe (llvm back end, O3, entry hello::Hello.$Module.Main)
timings: System.Core (compiled library) 83 ms, frontend 1536 ms, HIR link 54 ms, lowering 619 ms, IR checks 226 ms, IR link 93 ms, native (llvm) 1551 ms; total 4173 ms
hello.exe
Hello from Larva!
| Phase | What runs | Where |
|---|---|---|
System.Core (compiled library) |
Reads the standard library's HIR from System.Core.dll (or compiles it from source in a working copy, System.Core (compiled now), and caches it). |
SourceBuild.CoreLibrary |
<Name> (<Mode>) |
A dependency whose gc: differs from the program's, compiled and lowered on its own as a separate GC domain. |
SourceBuild.DomainLibrary |
frontend |
The language pack's compile call: source text to an HIR assembly. |
the pack, in larva's process |
HIR link |
System.Core, libraries, bindings and the program merged into one assembly. | HirLinker.Link |
lowering |
HIR to Larva IR. | HirLowerer.Lower |
borrow check |
Only with --check and a mode other than off. |
BorrowChecker.Check |
IR checks |
Type, region and borrow checks of the module, ready to link. | Compiler.CompileObject |
IR link |
One linked program with an entry. | Linker.Link |
native (llvm), native (x64), native (wasm-llvm), native (wasm) |
Code generation, the runtime, the system linker. | ExecutableBuilder, WasmBuilder |
The same build with the other back ends differs only in the last step:
larva build --backend x64 --timings -o hellox.exe hello.ant
hellox.exe (x64 back end, entry hellox::Hello.$Module.Main)
timings: System.Core (compiled library) 47 ms, frontend 1070 ms, HIR link 62 ms, lowering 632 ms, IR checks 230 ms, IR link 100 ms, native (x64) 979 ms; total 3132 ms
larva build --timings --target wasm-llvm -o hello.js hello.ant
hello.wasm, hello.js, hello.html (LLVM back end, O3, entry hello::Hello.$Module.Main)
timings: System.Core (compiled library) 68 ms, frontend 1077 ms, HIR link 56 ms, lowering 598 ms, IR checks 208 ms, IR link 84 ms, native (wasm-llvm) 1705 ms; total 3808 ms
node hello.js
Hello from Larva!
And --check stops after lowering (and the borrow check, when it is on), writing nothing:
larva build --check --borrowcheck enforce hello.ant
no errors (1 file; System.Core (compiled library) 40 ms, frontend 934 ms, HIR link 50 ms, lowering 574 ms, borrow check 134 ms; total 1738 ms)
These timings come from a working copy of larva; the installed one is compiled ahead of time and is several times faster in every phase.
The forms of a program
A program changes shape four times. Each form exists for one reason.
| Form | What it is | Made by | Read by | On disk |
|---|---|---|---|---|
| Source | Text in some language. | You | The language pack | .ant, … |
| HIR | The program as a language sees it: namespaces, classes, interfaces, generics, attributes, typed bodies with statements and expressions. Names are resolved and every expression has a type, but nothing is decided about how it runs. | Frontends | Lowering, the catalog, language views, the editor | .lva, or a .lva section in a .dll |
| Larva IR | The program as a machine sees it, but still portable: structs, gc handles, places, basic blocks, terminators. Generics are still generic (with requirements). |
Lowering | Checks, the linker, every back end | .lvo (one module), .lvm (linked) |
| IL | A compact bytecode lowered from linked IR, encoded in 4-bit units. | IlLowering |
The VM | inside a .lvm |
| Machine code | x86-64 or WebAssembly. | LLVM, the x64 back end, the own Wasm back end | The processor, the system linker, a WebAssembly engine | .obj, .exe, .dll, .wasm |
The split between HIR and IR is the central decision of Larva's design. Before it, the Antril compiler lowered every feature (classes, closures, async, reflection, boxing) straight to the low-level IR, and every library was read by reparsing the text of its declarations. Now:
- HIR is the truth of the program. Types, members, generics, attributes and typed bodies, with complete metadata. Every frontend, tool and library speaks HIR.
- The language does not decide how code runs. A frontend resolves names, overloads, types and inference and emits typed HIR. How a virtual call is dispatched, how a closure is built, how an async method becomes a state machine: Larva decides, in lowering. Two languages that both have classes get the same object layout and can call each other.
- Libraries are referenced by HIR metadata, not by source.
System.Core.dllholds the HIR of the standard library; compiling against it reads a binary table instead of parsing thousands of lines. - Everything native is
extern. The runtime's services are reached through a fixed table of intrinsics, the same in every back end and in the VM.
IR, below HIR, is where memory is explicit: object headers, handles, borrows. That is why the borrow checker, the region checker and the GC domains work on IR: whatever language a program came from, the same rules hold.
The projects of Larva
Larva is a set of libraries with one command on top. Each depends only on the ones in the rows above it:
| Layer | Projects | Depend on |
|---|---|---|
| Models | Larva.IL, Larva.Hir, Larva.Native |
nothing in Larva |
| IR | Larva.IR |
Larva.IL |
| Services over the models | Larva.Hir.Services |
Larva.Hir |
Larva.Hir.Lowering |
Larva.Hir, Larva.IR |
|
Larva.Runtime (the VM) |
Larva.IR |
|
Larva.Build |
Larva.IR |
|
| Back ends | Larva.Llvm, Larva.X64 |
Larva.IR, Larva.Native |
Larva.Wasm |
Larva.IR |
|
| Tools | Larva.Driver |
Larva.IR, Larva.Native, Larva.Llvm, Larva.X64, Larva.Wasm |
Hive.Core |
Larva.Build |
|
Larva.Bindings |
Larva.Hir, Larva.Hir.Services, Larva.Build |
|
| Command | Larva.Cli (larva) |
all of the above |
| Installer | Larva.Setup |
nothing (it copies a published larva) |
Larva.Hir depends on nothing so that a frontend can be built on the HIR model and its services (the Antril pack uses Larva.Hir, Larva.Hir.Services and Larva.IR), without the back ends, the runtime or the command.
| Project | What it does | Pages |
|---|---|---|
Larva.Hir |
The HIR model, its text form, the .lva encoding, linking HIR assemblies. Depends on nothing. |
HIR, The .lva format |
Larva.Hir.Services |
The catalog of types and members, language views (HIR written back as source), the editor services. | Catalog and views |
Larva.Hir.Lowering |
HIR to IR: layouts, vtables and itables, generics, closures, iterators, async, exceptions, reflection, interop, static constructors. | Lowering, Lowering language features |
Larva.IR |
The IR: types, places, rvalues, terminators, modules; the checkers (types, regions, borrows); the monomorphizer and the coroutine pass; .lvo/.lvm encoding; the linker; GC configs. |
Larva IR, Borrow checker, Objects and linking |
Larva.IL |
The IL: opcodes, the 4-bit encoding, the peephole pass, the disassembler. | IL and VM |
Larva.Runtime |
The VM that runs IL, with its own heap and collectors. | IL and VM |
Larva.X64 |
Larva's own x86-64 code generator and COFF writer. | x86-64 back end |
Larva.Llvm |
Code generation through LLVM. | LLVM back end |
Larva.Wasm |
Larva's own WebAssembly back end. | WebAssembly |
Larva.Native |
The native runtime larva_rt.c, its in-process twin NativeRuntime, and finding the system toolchain. |
Runtime, Garbage collection |
Larva.Driver |
The builders: executables and libraries, WebAssembly output. | Native builds |
Larva.Build |
.queen files: syntax, schema, projects, machine defaults. |
Projects and builds |
Hive.Core |
Packages: archive, manifest, keys, cache, registry. | Hive internals |
Larva.Bindings |
Native export tables, .bind descriptions, the C header reader, the binding generator. |
Bindings internals |
Larva.Cli |
The larva command, language pack loading, the language server, source builds, binding profiles. |
Language packs, Language server |
Larva.Setup |
The Windows installer. | Installers |
Library |
System.Core and System.Bindings, written in Antril, compiled into .dll libraries when an installer is built. |
System.Core overview |
The language packs are not in this list: each lives in its own repository and is loaded by larva at run time (see Language packs).
One request, four runtimes
Code compiled by Larva can run in four places, and each has a runtime that implements the same object layout and the same table of intrinsics:
| Where the code runs | Runtime | Used by |
|---|---|---|
| A native executable or library | larva_rt.c, compiled once per machine and linked in, with no C library |
larva build, larva run |
| larva's own process | NativeRuntime, a managed twin of larva_rt.c |
the x64 back end's in-memory images, binding profiles, the LLVM in-memory path |
| A WebAssembly engine | larva_rt.js (with --target wasm-llvm, also wasm_heap.ll linked into the module for inline allocation) |
--target wasm, --target wasm-llvm |
| The VM | Larva.Runtime (Interpreter, Heap) |
larva run <module.lvm> |
Because all four agree, a program gives the same output wherever it runs; the VM is the reference the other three are compared with.
The files Larva reads and writes
| Extension | What it is | Page |
|---|---|---|
.queen |
A project: what to build and how. | Projects and builds |
.lva |
An HIR assembly. | The .lva format |
.dll (Larva library) |
A PE file whose .lva section holds an HIR assembly: System.Core.dll, larva lib and larva bind output. |
The .lva format |
.lvo |
One verified IR module, before linking. | Objects and linking |
.lvm |
A linked program: IR, IL, or both. | Objects and linking, IL and VM |
.bind |
A description of a native library's functions and types. | Bindings internals |
.hive |
A signed package. | Hive internals |
language.json |
A language pack's manifest. | Language packs |
What is not implemented yet
These pages describe the code as it is. Where it falls short of the design, the page says so. The main gaps today:
gc: customis accepted but not usable: the runtime has hooks for an installed collector, but the library has noIGarbageCollectorinterface and noGC.Installyet.- Larva's own WebAssembly back end emits invalid modules for some programs (any program that builds text, for example), and does not support 256-bit integers; use
--target wasm-llvm. Main(str[] args)cannot be a program's entry, andMain() : i32prints its result instead of exiting with it.- Native builds need the MSVC tools: the Linux and macOS builders exist but no command reaches them yet.
larva buildrecompiles everything on each build. An incremental cache per assembly is planned.
Editar esta página en GitHub Reportar un problema