v3 Bytecode Format (BC2)
Work through examples, try the reasoning yourself, then put it into practice.
View SlidesBefore you start
- Trace v3 stack operations and function IDs.
- Encode/decode BC1 sections and quoted strings.
What you will practice
- Explain the BC1-to-BC2 call representation change.
- Reconstruct closure creation before a callable-value CALL.
- Test format fidelity separately from semantic bytecode validity.
In this lesson
Lesson
3 min readv3 Bytecode Format (BC2)
BC2 extends the artifact with numeric function IDs and value-based calls. It begins in v3, before modules exist. v5 later links separately compiled BC2 compatible objects; there is no linking step in this module.
Worked reconstruction
A complete callable-value example is:
BC2
FUNC 0 difference a b
LOAD a
LOAD b
SUB
RETURN
END
MAIN
MAKE_CLOSURE 0
PUSH_NUM 9
PUSH_NUM 2
CALL 2
END
MAKE_CLOSURE puts a callee below the two arguments. CALL 2 pops both arguments and that callee, then returns one value. Omitting MAKE_CLOSURE may still produce structurally parseable text, but the resulting program has no callable operand. A decoder is not automatically a stack verifier.
What changes and what stays
BC1 uses FUNC name params... and CALL name arity; BC2 uses
FUNC id name params... and CALL arity. MAKE_CLOSURE carries a function ID.
MAKE_ARRAY/MAKE_MAP carry counts; GET_INDEX/SET_INDEX carry no operands. Names,
parameter order, explicit IDs, instruction order, and string contents must
survive Encode→Decode. Use the version header rather than guessing call syntax
from an ambiguous line.
Jumps remain instruction indexes within Main or a function's code slice. Function section positions in the text are not IDs. IDs can be emitted in a different order from slice positions because nested function bodies complete before their enclosing body. Preserve the explicit numbers instead of renumbering during decoding.
Verification layers
Test structural round trips, independent known artifacts, malformed instruction operands, and runtime behavior. Matching encoder/decoder mistakes can survive a round trip. Conversely an artifact can decode and still attempt to call a number or index an invalid value. The course does not promise a comprehensive bytecode verifier or safe execution of arbitrary hostile artifacts.
Debugging lab
A BC1 migration replaces the line CALL difference 2 with CALL 2 but changes nothing else in Main. Why can Decode succeed while execution fails?
Compare your diagnosis after attempting the lab
BC2 CALL requires a closure value below the arguments. A name embedded in BC1 CALL used to identify the function without that operand. Add MAKE_CLOSURE or LOAD of a closure binding before the arguments; textual validity alone cannot supply it.
Transfer task
Author two functions with IDs 3 and 1 in that order and Main creating closure 1. Predict which function executes after a round trip. Then add a comment before a jump and explain why the target number does not change.
Carry forward
Carry a standalone BC2 artifact into the v3 integration gate. It must execute without AST, name-analysis scopes, or in-memory closure instances from compilation.
Build bytecode-io-v3. Keep a before/after trace of one failing test. Use the checkpoint to diagnose specific skills; passing it does not replace implementing and testing the artifact.
Practice sequence
Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.