Expand description
§bytecode_lang
LSB, the LexerSketch bytecode format: one register-machine instruction set for every language and every execution tier, its module model, a versioned binary encoding, a budgeted decoder, a deterministic disassembler, and a builder that resolves branch labels.
The VM (bvm-lang 2.0) executes LSB, code generators (codegen-lang 2.0) emit it, program images (loader-lang) store it, and the debugger (dap-lang) reads its line tables. This crate owns the format only; it executes nothing.
§Quick start
Build a function, encode the module, decode it back, and read the listing:
use bytecode_lang::{decode, disassemble, encode, Inst, IntOp, IntTy, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let mut f = m.function("add", &[ValType::I64, ValType::I64], &[ValType::I64]);
let (a, b) = (f.param(0), f.param(1));
let sum = f.reg(ValType::I64);
f.emit(Inst::IAdd { dst: sum, lhs: a, rhs: b, op: IntOp::new(IntTy::I64) });
f.ret(sum);
m.add_function(f)?;
let module = m.finish()?;
let bytes = encode(&module);
let back = decode(&bytes)?;
assert_eq!(back, module);
assert!(disassemble(&back).contains("iadd.i64 r2, r0, r1"));§The model
- Registers, typed. Every function has a frame of 64-bit registers,
each with a declared
ValType: unboxed scalars for static languages,ValType::Dynfor dynamic values, and references. Declared types make GC roots exact and let the verifier check every operand. - Eight-byte instructions.
Instis aCopyenum of eight bytes; a function body is a flat&[Inst]that an interpreter walks without re-parsing. Branch targets are resolved instruction indices. - Policies on every operation. Integer instructions carry an
IntOp(the operand type plus the overflow, division-by-zero, and shift policies), dynamic ones aPolicy, float-to-integer conversions aFloatConv, so every tier computes the same result or raises the sameErrorKind. - Dynamic languages built in.
dynarithmetic and comparisons with a numeric fast path, ordered hash maps, property access, iteration, and per-moduleHooks that let a language supply its own semantics for the slow path.overflow = promotegives PHP’s int-to-float arithmetic,shift = saturateits shifts. - PHP’s value and reference semantics.
dsep_indexseparates a nested array only when it may be shared; references into map slots and properties (dref_index,dbind_index) are transparent in their slots and survive copies as PHP’s do. - Dynamic calls with real signatures. A function or import may carry a
ParamList(names, rest parameters, defaults, by-reference parameters);dcall_shapepasses named and spread arguments through aCallShape, andParamList::bindis the one binding rule every tier applies. - Coroutines. Stackful coroutines (
coro_new,yield,await,resume,spawn) for generators, fibers, and async tasks; seeCoroState.
The normative description of every instruction is specs/LSB.md in the
LexerSketch plan; docs/API.md documents every public item.
§Guarantees
decodenever panics on any input, never recurses, and allocates no more than itsLimitsand the input length justify.decode(&encode(&m)) == Ok(m)for every module, andencode(&decode(bytes)?) == bytesfor every accepted input: each module has exactly one encoding.encodeanddisassembleare deterministic.- A function produced by
ModuleBuilder::add_functionhas no unresolved or out-of-range branch target.
What this release does not do: verify a module’s meaning (index
ranges, register types, frame shapes). That is the v0.5 verifier, whose
rules are specified in specs/LSB.md §8. Until then a decoded module is
well-formed but unverified.
Structs§
- Binding
- The result of
ParamList::bind: what each parameter receives, and the presence mask. - Call
Shape - The argument layout of a
dcall_shapecall site: one entry per window register (dst+1 ..= dst+len), saying whether that argument is positional, named, or spread. Shapes live in a per-function table and are named by aShapeId. - ConstId
- An index into the module’s constant pool.
- Decode
Error - Why bytes are not a module, and where.
- Export
- A named item the module exports: the shared module interface the loader links native and bytecode units through.
- Field
- A named, typed field of a
StructDef. - Field
Idx - A field slot of a struct type, counted across the whole parent chain (a struct’s fields start with its parent’s).
- Field
Spec - One operand of an opcode: its field name, its kind, and its slot.
- Float
Conv - The modifier byte of
Inst::F32ToIntandInst::F64ToInt: the destination integer type and thefloat_to_intpolicy for NaN and out-of-range values. - FuncId
- An index into the module’s function table.
- Func
Type - A function signature.
- Function
- One function of a module: its frame layout, its tables, its code, and its debug information.
- Function
Builder - Builds one function. Created by
ModuleBuilder::function, added back withModuleBuilder::add_function. - Global
- A module-level variable.
- Global
Id - An index into the module’s global table.
- Handler
- An exception-handling region: an error raised by an instruction at a pc
in
start..endtransfers control totargetwith the error value incatch. - Hook
Binding - One bound
Hook. A module binds each hook at most once; bindings are kept sorted by hook code. - Import
- A host function the module calls by index
(
Inst::CallImport), bound by the loader bymoduleandname. - Import
Id - An index into the module’s import table (host functions).
- IntConv
- The modifier byte of
Inst::IntCast: source type, destination type, and theoverflowpolicy for values that do not fit. - IntOp
- An integer type plus the policies integer arithmetic consults: the modifier byte of every typed integer instruction that computes an integer.
- IntPair
- The modifier byte of the bit-level conversions
(
Zext,Sext,Trunc), which never raise an error and so carry no policy. - Jump
Table - A jump table of
Inst::Switch:targets[v]for a selectorvin range,defaultotherwise. - Label
- A position in a function’s code, named before it is known.
- Limits
- The budgets the decoder enforces on untrusted input.
- LineRow
- A row of a function’s line table: instructions from
pcup to the next row’spccame from this source position. - Local
Var - A named source variable living in a register over a pc range, for debuggers.
- Method
- A named method of a
StructDef: the function receives the instance as its first parameter. - Module
- A complete LSB module: the unit that is encoded, decoded, verified, loaded, and disassembled.
- Module
Builder - Builds a
Module. - NameRef
- An index into the running function’s name list, which maps it to a
StrId. - Param
- One parameter of a
ParamList. - Param
List - The dynamic-call signature of a function or an import: what lets a
dcallordcall_shapepass named, spread, extra, missing, and by-reference arguments (specs/LSB.md§5.15). - Policy
- The complete OPS policy set, packed into six bits: the modifier byte of
every dynamic arithmetic instruction (
dadd,dshl,dpow, …). - Reg
- A register in the running function’s frame.
- ShapeId
- An index into the running function’s call shapes (see
Inst::DCallShapeandCallShape): which window arguments are positional, named, or spread. 16-bit, likeNameRef, so a function may use 65,536 distinct shapes. - StrId
- An index into the module’s string table.
- Struct
Def - A struct (record) type.
- TableId
- An index into the running function’s jump tables (see
Inst::Switch). - Target
- An instruction index within one function: the destination of a branch.
- TypeId
- An index into the module’s type table.
- TypeRef
- An index into the running function’s type list, which maps it to a
TypeId. - Upval
Idx - A captured value of the running closure (see
Inst::GetUpval).
Enums§
- ArgItem
- One argument of a dynamic call, as
ParamList::bindsees it. - ArgKind
- One argument of a
CallShape. - Bind
Error - Why a dynamic call’s arguments do not bind (
ParamList::bind). A VM raisesArgumentError(E0114) for every variant; the variant is the detail a diagnostic can show. - Bound
- What one parameter received from
ParamList::bind. - Build
Error - Why a function or module could not be built.
- Callee
- A function the module can call: one of its own, or an import.
- Const
- An entry of the module’s constant pool.
- Coro
State - The state of a coroutine, as
Inst::CoroStatusreports it (au8code). - Decode
Error Kind - What is wrong with the input; see
DecodeError. - DivZero
- The
div_zeropolicy: what integer div, rem, floor_div, and floor_mod do when the divisor is zero. - Error
Kind - A runtime error kind with its stable code.
- Export
Item - What an
Exportmakes visible to other units. - Field
Kind - What an operand is: the type of one
Instfield. - Float
ToInt - The
float_to_intpolicy: what float-to-integer conversion does with NaN or an out-of-range value. - FloatTy
- A floating-point type (IEEE 754 binary32 or binary64).
- Hook
- A dynamic-operation hook: the function a dynamic instruction calls when
its built-in fast path does not apply (for example
daddon two strings, orget_propon an object with no such field). - Inst
- One LSB instruction, decoded.
- Inst
Error - Why eight bytes are not an instruction.
- IntTy
- An integer type: the width and signedness an integer instruction works at (OPS §1).
- Kind
- The kind of a dynamic value: what
Inst::TypeOfreturns andInst::IsKindtests. - Limit
- Which budget a
DecodeErrorKind::LimitExceededrefers to. - Opcode
- The operation an
Instperforms: its first encoded byte. - Overflow
- The
overflowpolicy: what integer add, sub, mul, neg, abs, signedMIN / -1, andint_castdo when the exact result does not fit. - Param
Error - Why a
ParamListis malformed, or does not fit the signature it is attached to. - Param
Kind - How a parameter of a
ParamListreceives arguments. - Prim
- A static representation crossing the
dynboundary: the modifier ofInst::ToDynandInst::FromDyn. - Shape
Error - Why a
CallShapeis malformed. - Shift
- The
shiftpolicy: what shl and shr do when the amount is at least the bit width, or negative for a signed amount. - Slot
- Where an operand lives in the eight-byte instruction word.
- TypeDef
- An entry of the module’s type table.
- ValType
- The declared type of a register, a global, a field, or a parameter.
Constants§
- FORMAT_
VERSION - The format version this crate writes and the only one it reads.
- MAGIC
- The four bytes every encoded module starts with:
LSB\0.
Functions§
- decode
- Decodes a module with the default
Limits. - decode_
with - Decodes a module with explicit budgets.
- disassemble
- The module’s disassembly: a deterministic text listing of every table and every function, with branch targets as labels and names resolved in comments.
- encode
- Encodes a module into its canonical bytes.