Calling Conventions
RukaLang has two internal call boundaries that matter for compiler work:
- MIR-level ownership and representation conventions.
- Backend ABI conventions (Rust emission and direct WASM emission).
This page documents the current rules and points to the rustdoc pages where those rules are encoded.
MIR-Level Contract
MIR stores both ownership mode and runtime/storage representation. Together, these define how a value is passed at call boundaries.
- Function parameter ownership is represented by
MirOwnershipMode. - Call-site argument ownership is represented by
MirArgMode. - Parameter boundary metadata is normalized through
MirParamBinding. - Call argument metadata is normalized through
MirCallArgBinding. - Local runtime/storage shape is represented by
MirLocalRepr.
Current boundary semantics:
Viewparameters are source-level read-only access;MutBorrowparameters are mutable borrow access;Ownedparameters are value transfer parameters.MirParamBinding::source_reprandMirParamBinding::local_reprdefine source boundary shape vs lowered local shape.MirParamBinding::requires_materializationmarks parameters where the lowered local representation differs from the source boundary representation.MirParamBinding::materializes_view_from_ownedmarks the current materialized view case where a source owned value is projected into a view-local boundary.MirCallArgBinding::requires_deref_readmarks call arguments that need a load/read from a place local before value passing.- Boundary coercions that require runtime checks currently lower at MIR call
sites with explicit
CollectionLencomparisons andCallExtern("std::panic")on failure.
Core MIR container docs:
Rust Backend Convention
Rust codegen follows Rust-level references/values directly:
- Internal calls (
MirInstr::Call) lower withemit_internal_call_args. - Runtime/extern calls (
MirInstr::CallExtern) lower withemit_extern_call_args.
Behavior by argument mode:
Borrowed(view call arg mode) passes&T(or&*placewhen the local is place-shaped).MutableBorrowpasses&mut T(or&mut *placefor mutable place locals).OwnedMovepasses by move; place reads are cloned from dereference.OwnedCopypasses a cloned value; place reads are cloned from dereference.
For slice place reads copied into owned values, Rust emission uses .to_vec()
instead of (*place).clone().
Entry points:
WASM Backend Convention
The direct WASM backend uses a strict, explicit ABI with normalized value types and out-slot returns for aggregate return values.
Signature shaping is defined by:
Current value mapping:
i64lowers toi64.- Most other runtime values lower to pointer-sized
i32handles (including strings, pointers, arrays, tuples, structs, enums, slices, and references).
Return conventions:
- Non-aggregate mutable-borrow params use an inout convention: argument value in, updated value returned as an extra WASM result.
- Scalar-like returns use normal WASM result values.
- Aggregate returns (currently tuple/struct/slice) use an out-slot pointer
parameter inserted at parameter index
0and no WASM result. - Aggregate temporaries are placed on the runtime shadow stack when required.
For the full shadow-stack lifecycle and memory layout, see WASM Shadow Stack.
Call lowering is defined by:
The call-argument strategy is selected from local representation and arg mode:
- Pass-through by value for normal value locals and mutable-borrow pointer ABI args.
- Dereference-load for mutable-borrow inout args when the source local is a non-passthrough place.
- Dereference-load to match callee ABI when reading from place-shaped locals.
Backend entry points:
Runtime WASM ABI Surface
Runtime-call ABI metadata is centralized in ruka_runtime:
The coercion runtime trap path is exposed as std::panic in this descriptor
table.
This descriptor table is what the WASM backend linker and call lowering use for symbol resolution and runtime signature checks.