#[repr(u8)]pub enum Opcode {
Show 47 variants
Const = 0,
Pop = 1,
Dup = 2,
GetLocal = 3,
SetLocal = 4,
GetGlobal = 5,
SetGlobal = 6,
Add = 7,
Sub = 8,
Mul = 9,
Div = 10,
Mod = 11,
Neg = 12,
FAdd = 13,
FSub = 14,
FMul = 15,
FDiv = 16,
FNeg = 17,
Eq = 18,
Ne = 19,
Lt = 20,
Le = 21,
Gt = 22,
Ge = 23,
FEq = 24,
FNe = 25,
FLt = 26,
FLe = 27,
FGt = 28,
FGe = 29,
Not = 30,
Jump = 31,
JumpIfFalse = 32,
JumpIfTrue = 33,
Call = 34,
Return = 35,
MakeArray = 36,
MakeTuple = 37,
MakeStruct = 38,
MakeEnumVariant = 39,
Index = 40,
Field = 41,
Len = 42,
ToStr = 43,
ConcatN = 44,
MatchVariant = 45,
Halt = 255,
}Expand description
the bytecode opcode set.
one byte per opcode, dense discriminants 0..=45 for the active set plus
Opcode::Halt at 0xFF as the decoder’s “unknown / end-of-stream”
sentinel. derives Copy because opcodes flow through codegen and the
peephole optimizer by value; one byte is cheaper to copy than to
reference.
the discriminants are part of the bytecode format – changing them reshapes every compiled chunk. add new opcodes by appending discriminants above the current high-water mark; never reuse a freed discriminant.
Variants§
Const = 0
push the constant pool entry at index u16 onto the stack. emitted
for every literal and for every constant-folded result.
Pop = 1
discard the value on top of the stack. emitted at statement-expression boundaries and after expressions whose result is unused.
Dup = 2
duplicate the value on top of the stack. used by MATCH_VARIANT chains
so multiple arms can test the same scrutinee.
GetLocal = 3
read local slot u16 and push its value. slots are numbered 0..N per
call frame; parameters occupy slots 0..argc.
SetLocal = 4
pop the top value and store it into local slot u16. used by let mut
rebinding and by loop-variable updates.
GetGlobal = 5
read the global variable at index u16 and push its value. globals are
keyed by name in the Program.globals table.
SetGlobal = 6
pop the top value and store it into the global at index u16. Qala v1
has no top-level mutable bindings, so this is reserved for forward
compatibility.
Add = 7
pop two i64 values, push their sum. codegen emits this only when both
operands are statically i64-typed; constant folding intercepts the
all-literal case at codegen time.
Sub = 8
pop two i64 values, push their difference (lhs - rhs).
Mul = 9
pop two i64 values, push their product.
Div = 10
pop two i64 values, push their quotient (truncated toward zero).
Mod = 11
pop two i64 values, push their remainder (Rust’s % semantics).
Neg = 12
pop one i64, push its negation. emitted by the unary - operator on
i64-typed expressions.
FAdd = 13
pop two f64 values, push their sum (IEEE 754).
FSub = 14
pop two f64 values, push their difference (IEEE 754).
FMul = 15
pop two f64 values, push their product (IEEE 754).
FDiv = 16
pop two f64 values, push their quotient (IEEE 754).
FNeg = 17
pop one f64, push its negation (sign-bit flip).
Eq = 18
pop two values of equal type (i64, bool, or str), push the bool result
of lhs == rhs. the VM dispatches by operand type at runtime.
Ne = 19
pop two values of equal type, push lhs != rhs.
Lt = 20
pop two values of equal type, push lhs < rhs.
Le = 21
pop two values of equal type, push lhs <= rhs.
Gt = 22
pop two values of equal type, push lhs > rhs.
Ge = 23
pop two values of equal type, push lhs >= rhs.
FEq = 24
pop two f64 values, push lhs == rhs. follows IEEE 754: NaN == NaN
is false.
FNe = 25
pop two f64 values, push lhs != rhs. follows IEEE 754: NaN != NaN
is true.
FLt = 26
pop two f64 values, push lhs < rhs (IEEE 754).
FLe = 27
pop two f64 values, push lhs <= rhs (IEEE 754).
FGt = 28
pop two f64 values, push lhs > rhs (IEEE 754).
FGe = 29
pop two f64 values, push lhs >= rhs (IEEE 754).
Not = 30
pop one bool, push its negation. short-circuiting && / || compile
to jump patterns, not dedicated opcodes; this is the only logic op.
Jump = 31
branch by the signed i16 offset relative to the byte AFTER the
operand. negative offsets allowed for backward jumps (loops).
JumpIfFalse = 32
pop one bool; if false, branch by the signed i16 offset relative
to the byte AFTER the operand. otherwise fall through.
JumpIfTrue = 33
pop one bool; if true, branch by the signed i16 offset relative to
the byte AFTER the operand. otherwise fall through. emitted by the
peephole rewrite NOT; JUMP_IF_FALSE -> JUMP_IF_TRUE.
Call = 34
call the function at Program.chunks[u16] with u8 arguments already
on the stack (top is the rightmost arg). pushes the returned value
(or [crate::value::Value::Void] for void-returning functions).
Return = 35
return from the current call frame; the value on top of the stack
becomes the call’s result. void-returning functions push
[crate::value::Value::Void] before this opcode.
MakeArray = 36
pop u16 values off the stack (top is the last element), push a heap
array containing them in stack order.
MakeTuple = 37
pop u16 values off the stack (top is the last element), push a heap
tuple containing them in stack order.
MakeStruct = 38
build a heap struct. the u16 operand is a struct id – an index into
Program.structs, NOT a bare field count. the VM reads the field
count from Program.structs[id].field_count, pops that many values
off the stack (top is the last field’s value), and labels the struct
with Program.structs[id].name. the field order is locked by the
struct declaration; codegen emits the values in declaration order so
the VM pairs them without a per-field name index.
MakeEnumVariant = 39
construct an enum variant value: variant id u16, then u8 payload
values already on the stack (top is the rightmost payload field). the
VM keeps the variant id and payload as a heap object.
Index = 40
pop an index (i64) then an array value, push the array’s element at that index. out-of-bounds is a runtime error.
Field = 41
pop a struct value, push the field at name-pool index u16. the VM
resolves the name to the struct’s declared field offset.
Len = 42
pop an array (or string), push its length as i64.
ToStr = 43
pop one value, push its string form. used to materialise interpolated
segments whose static type is not already str.
ConcatN = 44
pop u16 values off the stack (in stack order, top last), concatenate
them as strings, push the result. used to materialise string
interpolation.
MatchVariant = 45
test the value on top of the stack against variant id u16; on match,
leave the destructured payload on the stack; on miss, branch by the
signed i16 offset. consumes the scrutinee on match, leaves it on
miss (so a chain of MATCH_VARIANT over multiple arms tests against
the same scrutinee via DUP).
Halt = 255
sentinel discriminant 0xFF; never emitted by codegen but useful as
the disassembler’s “unknown byte” marker. the VM treats it as an
error.
Implementations§
Source§impl Opcode
impl Opcode
Sourcepub fn from_u8(b: u8) -> Option<Opcode>
pub fn from_u8(b: u8) -> Option<Opcode>
safe reverse lookup: the disassembler’s only entry from raw bytes back
to a typed Opcode. returns None for any undefined discriminant
rather than the UB that a transmute would risk. the match compiles
to the same branch table a transmute-based decode would, so the
safety is free.
Sourcepub fn name(self) -> &'static str
pub fn name(self) -> &'static str
the locked uppercase identifier per Opcode used by the
disassembler and the playground bytecode panel. one line per variant;
a missing arm fails to compile. the strings are part of the public
disassembler contract.
Sourcepub fn operand_bytes(self) -> u8
pub fn operand_bytes(self) -> u8
the number of operand bytes following this opcode in the instruction
stream. used by the peephole optimizer’s instruction-step function
and by crate::chunk::Chunk::disassemble to skip past operand
bytes when walking the byte stream. variants reading no operand
return 0; variants reading a u16 return 2; variants reading a
u16 + u8 return 3; variants reading a u16 + i16 return 4. v1 has
no wider operand layouts.