### Generate Standard Interpreter with `define_interpreter!` Source: https://context7.com/playx18/bytecodegen/llms.txt Generates a standard loop-based interpreter using the `define_interpreter!` macro. Requires defining the `ip` block for instruction pointer handling and specifying handlers for each opcode. ```rust #![feature(explicit_tail_calls)] use bytecodegen::{OperandWidth, bytecode_list}; bytecode_list! { section Bc { LoadConst { args { dst: usize, value: i32 } } Return { args { src: usize } } } } struct Vm { regs: [i32; 8] } // Standard loop-based interpreter generated::define_interpreter! { fn run(bytes: &[u8], pc: &mut usize, vm: &mut Vm) -> Option; ip { load = { if *pc >= bytes.len() { return None; } bytes.as_ptr().wrapping_add(*pc) }; store(next) = { *pc = unsafe { next.offset_from(bytes.as_ptr()) } as usize; }; } invalid(op, w) => return None, LoadConst(op) => { vm.regs[op.dst] = op.value; } Return(op) => return Some(vm.regs[op.src]), } fn main() { let linked = generated::link([ LoadConst::new(0, 7).into(), Return::new(0).into(), ]) .unwrap(); let mut vm = Vm { regs: [0; 8] }; let mut pc = 0usize; let result = run(linked.bytes(), &mut pc, &mut vm); assert_eq!(result, Some(7)); } ``` -------------------------------- ### Generate Tail-Call Interpreter with `define_tail_interpreter!` Source: https://context7.com/playx18/bytecodegen/llms.txt Generates a tail-call-based interpreter using `define_tail_interpreter!`. This approach uses `become` for zero-cost chaining between handlers and requires `#![feature(explicit_tail_calls)]`. ```rust generated::define_tail_interpreter! { fn run_tail(bytes: &[u8], ip: &mut *const u8, vm: &mut Vm) -> Option; ip { load = { *ip }; store(next) = { *ip = next; }; } invalid(op, w) => None, LoadConst(op) => { vm.regs[op.dst] = op.value; become run_tail(bytes, ip, vm) } Return(op) => Some(vm.regs[op.src]), } ``` -------------------------------- ### Declare Bytecode Schema with `bytecode_list!` Macro Source: https://context7.com/playx18/bytecodegen/llms.txt Use the `bytecode_list!` macro to define sections, opcodes, groups, and encoding directives for a bytecode format. This generates typed instruction structs, enums, and helper functions for linking, verification, and interpretation. ```rust use bytecodegen::{Emit, Label, LinkedBytecodeView, OperandWidth, bytecode_list}; bytecode_list! { section Bytecode { preserve_order = false; LoadConst { args { dst: usize, value: i32 } } group BinaryOp = [Add, Sub] { args { dst: usize, lhs: usize, rhs: usize } } JumpIfZero { args { reg: usize, #[relocatable] target: i32, } } Jump { args { #[relocatable] target: i32, } } Return { args { src: usize } } } } fn main() { // Construct individual instructions with typed constructors let instr = LoadConst::new(0, 42); // Emit at the smallest fitting width let (width, bytes) = instr.emit_smallest_to_vec().unwrap(); assert_eq!(width, OperandWidth::Narrow); // Assemble a program using labels for forward-reference resolution let loop_check = Label::new(); let done = Label::new(); let linked = generated::link([ LoadConst::new(0, 5).into(), // r0 = 5 LoadConst::new(1, 0).into(), // r1 = 0 (accumulator) LoadConst::new(2, 1).into(), // r2 = 1 (step) generated::bind(loop_check), JumpIfZero::linkable(0, done), // if r0 == 0 goto done Add::new(1, 1, 0).into(), // r1 += r0 Sub::new(0, 0, 2).into(), // r0 -= 1 Jump::linkable(loop_check), generated::bind(done), Return::new(1).into(), ]) .unwrap(); println!("bytecode bytes: {}", linked.bytes().len()); println!("instructions linked: {}", linked.instruction_count()); // Output: bytecode bytes: 21 // Output: instructions linked: 9 } ``` -------------------------------- ### Disassemble Bytes with Default Options Source: https://context7.com/playx18/bytecodegen/llms.txt Disassembles a byte stream into a human-readable string using default options. Shows byte offsets, raw bytes, and snake_case mnemonics. ```rust use bytecodegen::{DisassemblerOptions, Label, LinkedBytecodeView, MnemonicCase, bytecode_list}; bytecode_list! { section Bc { LoadConst { args { dst: usize, value: i32 } } Return { args { src: usize } } } } fn main() { let linked = generated::link([ LoadConst::new(0, 99).into(), Return::new(0).into(), ]) .unwrap(); // Default options: snake_case mnemonics, byte-offset labels, raw bytes shown let default_text = generated::disassemble_bytes(linked.bytes(), &(), &DisassemblerOptions::default()) .unwrap(); println!("{default_text}"); // [000] 0x00 0x00 0x63 load_const 0 99 // [003] 0x02 0x00 return 0 } ``` -------------------------------- ### Verify Bytecode Stack Balance and Jump Targets Source: https://context7.com/playx18/bytecodegen/llms.txt Use `#[verify]` attributes on opcodes to define invariants like stack balance or jump target validity. The `generated::verify` function checks these invariants against a linked instruction stream, returning errors for any violations. ```rust use bytecodegen::bytecode_list; bytecode_list! { section Vm { #[verify(stack_balance = 1)] Push { args { value: i32 } } #[verify(stack_balance = -1)] Pop { args { dst: usize } } #[verify(stack_balance = -1)] Return { args { src: usize } } } } fn main() { // Valid program: Push(42) then Return(0) — net stack balance = 0 let ok = generated::link(vec![Push::new(42).into(), Return::new(0).into()]).unwrap(); assert!(generated::verify(&ok).is_ok()); // Invalid program: Pop without a preceding Push — stack underflow let bad = generated::link(vec![Pop::new(0).into()]).unwrap(); match generated::verify(&bad) { Err(errors) => { assert!(errors[0].message().contains("stack underflow")); println!("caught: {}", errors[0]); // caught: verification error at instruction 0: stack underflow } Ok(()) => panic!("expected failure"), } } ``` -------------------------------- ### Disassemble Bytes with Custom Options Source: https://context7.com/playx18/bytecodegen/llms.txt Disassembles a byte stream with custom options, including UpperCamel mnemonics, no raw bytes, and instruction-index labels. Requires `DisassemblerOptions` to be configured. ```rust // Custom options: UpperCamel mnemonics, no raw bytes, instruction-index labels let opts = DisassemblerOptions { mnemonic_case: MnemonicCase::UpperCamel, show_bytes: false, label_kind: bytecodegen::DisassemblyLabel::InstructionIndex, ..DisassemblerOptions::default() }; let custom_text = generated::disassemble_bytes(linked.bytes(), &(), &opts).unwrap(); println!("{custom_text}"); // [000] LoadConst 0 99 // [001] Return 0 ``` -------------------------------- ### Link Bytecode with Debug Information Source: https://context7.com/playx18/bytecodegen/llms.txt Define custom debug information types within a section using `debug:`. Use `DebugTable` to tag instructions before linking, and `LinkedProgram` to access `LinkedDebugInfo` for mapping byte offsets to source locations. ```rust use bytecodegen::{DebugTable, LinkedBytecodeView, bytecode_list}; use bytecodegen::core::LinkedProgram; bytecode_list! { section Vm { debug: LineInfo { src: u32, line: u16 } LoadConst { args { dst: usize, value: i32 } } Return { args { src: usize } } } } fn main() { let mut table = DebugTable::new(); let id0 = table.insert(LineInfo { src: 0, line: 1 }); let id1 = table.insert(LineInfo { src: 0, line: 10 }); // Duplicate entries are deduplicated — same id returned let id0_again = table.insert(LineInfo { src: 0, line: 1 }); assert_eq!(id0, id0_again); let load: LinkableInstruction = LoadConst::new(0, 42).into(); let ret: LinkableInstruction = Return::new(0).into(); let result: LinkedProgram = link(vec![load.with_debug(id0), ret.with_debug(id1)], table).unwrap(); assert_eq!(result.bytecode.instruction_count(), 2); let info = result.debug_info.as_ref().unwrap(); // Look up source info by byte offset let li0 = info.at_offset(0).unwrap(); println!("offset 0 → src={}, line={}", li0.src, li0.line); // src=0, line=1 let second_offset = result.bytecode.instructions()[1].offset as usize; let li1 = info.at_offset(second_offset).unwrap(); println!("offset {} → src={}, line={}", second_offset, li1.src, li1.line); // offset 2 → src=0, line=10 } ``` -------------------------------- ### Link-time Symbol Binding with Label and RelocValue Source: https://context7.com/playx18/bytecodegen/llms.txt Use `Label::new()` to create unique symbols and `RelocValue` with `::linkable(...)` for fields marked `#[relocatable]`. `RelocValue::Label(label)` defers resolution, while `RelocValue::Value(v)` provides a concrete value. `generated::bind(label)` marks the label's definition point in the instruction stream, with the linker resolving all labels before emitting the final byte stream. ```rust use bytecodegen::{Label, RelocValue, bytecode_list}; bytecode_list! { section Bc { Nop {} Jump { args { #[relocatable] target: i32 } } Return {} } } fn main() { let skip = Label::new(); // Forward reference: Jump with label, resolved later by the linker let linked = generated::link([ Jump::linkable(skip), // jumps past the Nop Nop::new().into(), // skipped generated::bind(skip), Return::new().into(), ]) .unwrap(); println!("linked {} instructions", linked.instruction_count()); // linked 3 instructions (Nop is still encoded; jump skips execution to Return) } ``` -------------------------------- ### Define Packed Word Encoding for Bytecode Source: https://github.com/playx18/bytecodegen/blob/main/README.md Use `encoding = packed` to switch the schema to word-addressed instruction records. `word_bits = 32` is the currently supported setting. Opcodes without an explicit layout will have one synthesized. ```rust use bytecodegen::{bytecode_list}; bytecode_list! { encoding = packed { word_bits = 32 }; section Bytecode { LoadConst { args { dst: u8, value: i32 } } Add { args { dst: u8, lhs: u8, rhs: u8 } layout { word { op: 8, dst: 8, lhs: 8, rhs: 8 } } } } } fn main() { let words = LoadConst::new(0, 42).encode_packed_to_words().unwrap(); let decoded = LoadConst::decode_packed_words(&words).unwrap(); assert_eq!(decoded.dst, 0); assert_eq!(decoded.value, 42); } ``` -------------------------------- ### Packed 32-bit Word Encoding with bytecodegen Source: https://context7.com/playx18/bytecodegen/llms.txt Use `encoding = packed { word_bits = 32 }` to switch from variable-width byte streams to packed 32-bit word records. The macro synthesizes a layout automatically if not explicitly defined. This encoding is suitable for scenarios requiring fixed-size instruction words. ```rust use bytecodegen::bytecode_list; bytecode_list! { encoding = packed { word_bits = 32 }; section Bytecode { LoadConst { args { dst: u8, value: i32 } // layout synthesized automatically } Add { args { dst: u8, lhs: u8, rhs: u8 } layout { word { op: 8, dst: 8, lhs: 8, rhs: 8 } // stable external bit layout } } } } fn main() { // Encode to packed u32 words let words = LoadConst::new(0, 42).encode_packed_to_words().unwrap(); let decoded = LoadConst::decode_packed_words(&words).unwrap(); assert_eq!(decoded.dst, 0); assert_eq!(decoded.value, 42); // Encode to little-endian bytes derived from the packed words let mut bytes = Vec::new(); bytes.extend(LoadConst::new(0, i32::MAX).encode_packed_to_bytes().unwrap()); bytes.extend(Add::new(2, 0, 1).encode_packed_to_bytes().unwrap()); // Disassemble a packed byte stream let text = generated::disassemble_packed_bytes(&bytes, &(), &Default::default()).unwrap(); println!("{text}"); // [000] 0x00000000 0x7fffffff load_const 0 2147483647 // [001] 0x02010002 add 2 0 1 } ``` -------------------------------- ### Accessing Metadata Side-Tables with LinkedBytecodeView Source: https://context7.com/playx18/bytecodegen/llms.txt The `LinkedBytecodeView` trait provides access to the raw byte stream, instruction offsets, and typed metadata. Opcodes with a `metadata { ... }` block store a `metadata_id`, and typed payloads are accessed via `metadata_typed::(opcode_id, slot)`. Metadata can be mutated through a mutable view. ```rust use bytecodegen::{LinkedBytecodeView, bytecode_list}; bytecode_list! { section Bc { Call { args { func_id: u32, metadata_id: u32 } metadata { call_count: u64 } } Return {} } } fn main() { let linked = generated::link([ Call::new(0, 0).into(), Return::new().into(), ]) .unwrap(); // Read the raw encoded bytes println!("stream bytes: {:?}", linked.bytes()); // Access metadata side-table let call_opcode_id = 0usize; // depends on generated opcode ordering if let Some(meta) = linked.metadata_typed::(call_opcode_id, 0) { println!("initial call_count = {}", meta.call_count); // 0 } // Mutate metadata through the mutable view let mut linked = linked; if let Some(meta) = linked.metadata_typed_mut::(call_opcode_id, 0) { meta.call_count += 1; } } ``` -------------------------------- ### Explicit Layout for Packed Word Encoding Source: https://github.com/playx18/bytecodegen/blob/main/README.md Provide an explicit `layout` block to define a stable external bit layout for packed operands. This block must fully account for all operands and include `op: 8` in the first word. ```rust Add { args { dst: u8, lhs: u8, rhs: u8 } layout { word { op: 8, dst: 8, lhs: 8, rhs: 8 } } } ``` -------------------------------- ### Resolving Labels with generated::link Source: https://context7.com/playx18/bytecodegen/llms.txt Use `generated::link` to resolve `#[relocatable]` fields from labels to concrete offsets, build metadata, and return `NativeLinkedBytecode`. This function is essential for linking different parts of bytecode together, especially when using labels for jumps or references. ```rust use bytecodegen::{Label, LinkedBytecodeView, bytecode_list}; bytecode_list! { section Vm { LoadConst { args { dst: usize, value: i32 } } Add { args { dst: usize, lhs: usize, rhs: usize } } JumpIfZero { args { reg: usize, #[relocatable] target: i32 } } Return { args { src: usize } } } } fn main() { let done = Label::new(); let linked = generated::link([ LoadConst::new(0, 10).into(), LoadConst::new(1, 0).into(), JumpIfZero::linkable(0, done), // skip body if r0 == 0 Add::new(1, 1, 0).into(), generated::bind(done), Return::new(1).into(), ]) .expect("link failed"); // Access the raw byte stream let bytes = linked.bytes(); println!("encoded {} bytes, {} instructions", bytes.len(), linked.instruction_count()); // Walk the instruction index for entry in linked.instructions() { println!(" instruction at byte offset {}", entry.offset); } // encoded 14 bytes, 5 instructions // instruction at byte offset 0 // instruction at byte offset 2 // ... ``` -------------------------------- ### Define Custom Operand Types with `#[derive(Operand)]` Source: https://context7.com/playx18/bytecodegen/llms.txt Use the `#[derive(Operand)]` macro on `repr(u8/u16/u32)` enums to enable them as typed instruction arguments. The `#[operand(unsigned)]` attribute controls value widening for different instruction widths. ```rust use bytecodegen::{Emit, OperandWidth, bytecode_list}; use bytecodegen::Operand; #[derive(Debug, Clone, Copy, PartialEq, Eq, Operand)] #[repr(u8)] #[operand(unsigned)] enum RegKind { Local = 0, Capture = 1, Temp = 2, } bytecode_list! { section Bc { Load { args { kind: RegKind, index: u8, dst: u8 } } } } fn main() { let instr = Load::new(RegKind::Capture, 3, 0); let (width, bytes) = instr.emit_smallest_to_vec().unwrap(); assert_eq!(width, OperandWidth::Narrow); assert_eq!(bytes.len(), 4); // 1-byte header + 3 × 1-byte operands } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.