Help us shape the future of Go! Take the 2026 Go Developer Survey

bytecode

package
v0.38.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package bytecode defines the instruction set of the Kukel stack machine and the compiled program image.

An instruction is a one-byte opcode followed by fixed-width little-endian operands: u16 for indices (constants, slots, globals, argument counts) and u32 for jump targets (absolute offsets in the function's code).

Index

Constants

View Source
const (
	CmpLt = iota
	CmpLe
	CmpGt
	CmpGe
	CmpEq
	CmpNe
	CmpJumpIfTrue = 0x100
)

The comparison operand of CMP_JUMP: one of these, plus CmpJumpIfTrue to jump when the comparison holds (else when it does not).

View Source
const (
	MaxCodeSize   = 1 << 24
	MaxStackDepth = 1 << 20
)

MaxCodeSize and MaxStackDepth are the largest code size (bytes) and MaxStack of one function a .kkc file can hold; the compiler refuses bigger functions.

View Source
const FormatVersion = 11 // 2: milestone 12 superinstructions; 3: native modules (GlobalNative); 4: THROW takes only Error objects (Kukel v0.4); 5: jump tables and ADD_LOCAL (Kukel v0.8); 6: native base classes, CALL_NATIVE (Kukel v0.9); 7: ARITH_LK, CMP_JUMP_LK (Kukel v0.22); 8: INDEX_LL and the other fused forms of Kukel v0.26; 9: generators, GENERATOR, YIELD and ITER_CLOSE (Kukel v0.34); 10: GEN_RETURN (Kukel v0.35: a generator steps in the loop that walks it); 11: YIELD_VALUE and ITER_SEND (Kukel v0.37: send and yield from)

FormatVersion is the version of the .kkc format written by Encode.

Variables

This section is empty.

Functions

func Disassemble

func Disassemble(w io.Writer, p *Program) error

Disassemble writes a readable listing of the program.

func Encode

func Encode(p *Program) ([]byte, error)

Encode serializes a program.

func EncodeModule added in v0.7.0

func EncodeModule(m *Module) ([]byte, error)

EncodeModule serializes a module.

func LocalName added in v0.2.0

func LocalName(name string) string

LocalName returns the last part of a qualified name: "Stack" for "util::Stack". A class's constructor is the member function with the local name of the class.

func ReadU16

func ReadU16(code []byte, at int) int

ReadU16 reads a little-endian u16 operand (one bounds check, where binary.LittleEndian with a re-slice needs two: it is in every instruction with an operand).

func ReadU32

func ReadU32(code []byte, at int) int

ReadU32 reads a little-endian u32 operand (a jump target), as ReadU16.

func Relocate added in v0.7.0

func Relocate(f *Function, global, class, fn func(int) (int, error)) error

Relocate rewrites the global, class and function index operands of f's code with global, class and fn. A mapping can refuse an index with an error.

func StackUse

func StackUse(op Op, operands []int) (pops, pushes int)

StackUse returns how many values an instruction pops and pushes. For ITER_NEXT it is the path that continues the loop (the end of the loop pushes nothing); TRY_PUSH's handler starts with one more value than the instruction had.

func Verify

func Verify(p *Program) error

Verify checks that a program cannot make the VM crash: every index in an instruction refers to something that exists, jumps land on instructions, no function can run past its last instruction, and on every path the operand stack depth is the same at each instruction, never negative and never above the function's MaxStack. Decode calls it for every file; the compiler's output always passes. Try handlers are counted the same way: the same number at each instruction on every path, TRY_POP only with one registered, and none left when the function returns.

Types

type Class

type Class struct {
	Name    string
	Base    int      // index in Program.Classes, or -1
	Native  string   // a native base class (Base is -1): its qualified name ("strings::Builder")
	Fields  []string // own instance data members (the base's come first in an object)
	Statics []string // own static data members
	Methods []Method // own member functions
}

Class describes a class. A base class always comes before the classes derived from it in Program.Classes.

type Function

type Function struct {
	FuncName    string
	File        string // source file
	Line        int    // line of the definition
	NumParams   int    // required parameters
	NumOptional int    // optional parameters (with a default), after the required ones
	HasRest     bool   // a rest parameter follows the optional ones
	NumSlots    int    // parameters + locals + hidden slots (iterators, saved values)
	MaxStack    int    // operand stack depth needed above the slots
	Code        []byte
	Consts      []value.Value
	Lines       []LineInfo  // sorted by PC
	SlotNames   []string    // for the disassembler ("i/w": a slot two blocks share)
	Upvalues    []Upvalue   // a function literal's captured variables
	NumCaches   int         // inline cache slots of member instructions (the VM keeps the caches)
	Tables      []JumpTable // of SWITCH_TABLE instructions

	// Locals are the named parameters and locals with the code where each
	// is in scope, for the debugger. Only the compiler sets them (not in
	// files: the debugger runs from source).
	Locals []LocalInfo

	// Saved holds the opcodes that BREAK instructions replaced, by pc: only
	// in a copy of the code the debugger made (never in files).
	Saved map[int]Op

	// Index is the function's position in Program.Funcs (-1 for Init). It is
	// not stored in files: the compiler and Decode set it.
	Index int
}

Function is a compiled function: its code and constants.

func (*Function) LineAt

func (f *Function) LineAt(pc int) int

LineAt returns the source line of the instruction at pc.

func (*Function) Name

func (f *Function) Name() string

Name implements value.Named.

func (*Function) ParamSlots

func (f *Function) ParamSlots() int

ParamSlots is the number of slots that hold parameters.

func (*Function) Pos

func (f *Function) Pos() token.Pos

Pos returns the position of the function's definition.

type Global

type Global struct {
	Name  string
	Kind  GlobalKind
	Func  int // for GlobalFunc
	Class int // for GlobalClass
}

Global describes one global slot.

type GlobalKind

type GlobalKind uint8

GlobalKind says what a global slot holds when the program starts.

const (
	GlobalVar     GlobalKind = iota // a global variable (nil until initialized)
	GlobalFunc                      // a function: Funcs[Func]
	GlobalBuiltin                   // a built-in, looked up by name
	GlobalClass                     // a class: Classes[Class]
	GlobalNative                    // a function or class of a native module, looked up by its qualified name
)

type JumpTable added in v0.8.0

type JumpTable struct {
	Min     int64
	Targets []int
}

JumpTable maps the ints Min, Min+1, ... to code offsets (-1: none, the instruction's miss target).

type Layout added in v0.7.0

type Layout struct {
	Fields  []string // with the inherited ones first
	Statics []string
}

Layout is the data members of a class, which the code of member functions and of static data member accesses refers to by index: a program that links a module must have the same.

type LineInfo

type LineInfo struct {
	PC   int
	Line int
	// Cont: the code continues the line, it does not start it (a switch's
	// dispatch, after the body): the debugger does not stop there. Only
	// the compiler sets it (not in files: the debugger runs from source).
	Cont bool
}

LineInfo maps code from PC onwards to a source line.

type LocalInfo added in v0.27.0

type LocalInfo struct {
	Name       string
	Slot       int
	Start, End int
}

LocalInfo is a parameter or local: slot Slot holds it in the code from Start (after its initialization) to End (the end of its block).

type Method

type Method struct {
	Name   string
	Static bool
	Func   int // index in Program.Funcs, or -1 when declared but not defined
}

Method is a member function of a class.

type Module added in v0.7.0

type Module struct {
	Name    string
	Header  string      // its declarations, with empty function bodies and no initializers (Kukel source)
	Globals []Global    // what global indexes in Code stand for: Name and Kind
	Classes []string    // what class indexes stand for: class names
	Layouts []Layout    // the classes' data members when the module was compiled
	Funcs   []string    // the functions of others, after Code in the index space
	Code    []*Function // the module's own functions
	Init    int         // the function in Code that initializes its global variables
}

Module is a module compiled on its own (kukel build -module), for linking into programs that use it. Its code refers to globals, classes and other modules' functions by index into the name tables here; the compiler that links it finds them by name and relocates the code.

The module file (Encode's format with flags 1):

"KUKL", uv format version, uv flags (1)
str name, str header
uv n, globals          str name, byte kind
uv n, classes          str name, uv n + str data members (with the
                       inherited ones), uv n + str static data members
uv n, functions        str name: functions of other modules (and of
                       the prelude) the code calls, as Code index len(Code)+i
uv init                index in Code
uv n, code             functions
u32 CRC-32 (IEEE) of everything before it

func DecodeModule added in v0.7.0

func DecodeModule(data []byte) (*Module, error)

DecodeModule reads a module written by EncodeModule. Its code is checked when it is linked (Relocate, and Verify of the program).

type Op

type Op uint8

Op is an opcode.

const (
	OpNop Op = iota

	// Stack.
	OpConst // k u16: push Consts[k]
	OpNil
	OpTrue
	OpFalse
	OpPop
	OpDup
	OpDup2 // a b -> a b a b

	// Variables. Stores pop the value.
	OpLoadLocal   // slot u16
	OpStoreLocal  // slot u16
	OpLoadGlobal  // global u16
	OpStoreGlobal // global u16

	// Arithmetic and logic: pop operands, push the result.
	OpAdd
	OpSub
	OpMul
	OpDiv
	OpMod
	OpBitAnd
	OpBitOr
	OpBitXor
	OpShl
	OpShr
	OpNeg
	OpNot // push !truthy(x)
	OpBitNot
	OpEq
	OpNe
	OpLt
	OpLe
	OpGt
	OpGe
	OpInc // x + 1 (for ++)
	OpDec // x - 1 (for --)

	// Control.
	OpJump        // target u32
	OpJumpIfFalse // target u32: pop, jump if not truthy
	OpJumpIfTrue  // target u32: pop, jump if truthy
	OpJumpIfArg   // n u16, target u32: jump if argument n was passed (n < argc)

	// Calls. The callee is below its arguments on the stack.
	OpCall      // argc u16
	OpCallV     // call with the arguments in a vector on top of the callee
	OpReturn    // return the top of the stack
	OpReturnNil // return nil

	// Vectors: vector literals and the argument lists of spread calls.
	OpMakeVector // n u16: pop n values, push a vector of them
	OpAppend     // pop x, append it to the vector below
	OpExtend     // pop vector x, append its elements to the vector below

	// Collections.
	OpMakeMap  // n u16: pop n key/value pairs, push a map of them
	OpIndexGet // x i -> x[i]
	OpIndexSet // x i v -> v, after x[i] = v
	OpIterInit // x -> an iterator over x
	OpIterNext // slot u16, n u16, end u32: advance the iterator in slot; push n values, or jump to end

	// Classes and objects. Member names are string constants (u16 index).
	OpLoadThis    // push this
	OpLoadMember  // field u16: push this.fields[field]
	OpStoreMember // field u16: pop into this.fields[field]
	OpGetMember   // name u16, cache u16: obj -> obj->name (data member or bound method)
	OpSetMember   // name u16, cache u16: obj v -> v, after obj->name = v
	OpCallMethod  // name u16, argc u16, cache u16: obj args -> result of obj->name(args)
	OpCallMethodV // name u16, cache u16: obj argvector -> result
	OpCallDirect  // func u16, argc u16: obj args -> result of Funcs[func] with this = obj (Base::m(...))
	OpLoadFunc    // func u16: push Funcs[func] (a static member function)
	OpLoadStatic  // class u16, slot u16: push a static data member
	OpStoreStatic // class u16, slot u16: pop into a static data member
	OpNew         // argc u16: class args -> new object (the constructor runs)
	OpNewV        // class argvector -> new object

	// Exceptions.
	OpTryPush // kind u16, handler u32: register a handler (kind 0: catch, 1: finally)
	OpTryPop  // remove the innermost handler
	OpThrow   // pop an Error object and throw it (anything else: throw a TypeError)
	OpRethrow // pop a pending exception (from a finally handler) and throw it again

	// Closures. A captured local lives in a cell held by its slot.
	OpNewCell      // slot u16: pop a value into a new cell in the slot
	OpLoadCell     // slot u16: push the value in the slot's cell
	OpStoreCell    // slot u16: pop into the slot's cell
	OpLoadUpvalue  // index u16: push the value of the closure's captured cell
	OpStoreUpvalue // index u16: pop into the closure's captured cell
	OpClosure      // func u16: push a closure of Funcs[func] (see Function.Upvalues)

	// Superinstructions (milestone 12): common pairs fused into one.
	OpCmpJump  // cmp u16, target u32: pop b, a; jump if (a cmp b) == want (see CmpJump*)
	OpIncLocal // slot u16: slot++ (a statement: no value is pushed)
	OpDecLocal // slot u16: slot--

	// Jump tables (Kukel v0.8): a switch whose case values are dense ints.
	OpSwitchTable // table u16, miss u32: pop x; jump to Tables[table]'s target for x, else to miss
	OpAddLocal    // slot u16: pop x; slot = slot + x (statement "local += x")

	// Native base classes (Kukel v0.9).
	OpCallNative // class u16, name u16, argc u16: this args -> result of the member function name of the native class in global class, on this (Base::m(...))

	// The debugger (Kukel v0.15).
	OpBreak // the start of a source line in code the debugger copied: its hook, then the instruction Function.Saved holds for this pc

	// A local and a constant as the operands (Kukel v0.22): "n - 1", "n < 2".
	OpArithLK   // op u16, slot u16, const u16: push slot op Consts[const]; op is one of ADD to SHR
	OpCmpJumpLK // cmp u16, slot u16, const u16, target u32: jump if (slot cmp Consts[const]) == want, as CMP_JUMP

	// More of the same (Kukel v0.26), for the patterns programs run most.
	OpIndexLL    // x u16, i u16: push x[i], both locals: "v[i]"
	OpGetMemberL // slot u16, name u16, cache u16: push slot->name, as GET_MEMBER: "p->next"
	OpArithLL    // op u16, slot u16, slot u16: push slot1 op slot2, as ARITH_LK: "a * b"
	OpCmpJumpLL  // cmp u16, slot u16, slot u16, target u32: as CMP_JUMP_LK, with a local on the right: "i < n"
	OpArithK     // op u16, const u16: x -> x op Consts[const]: "x * y + 1"
	OpCmpJumpK   // cmp u16, const u16, target u32: x -> ; as CMP_JUMP, with Consts[const] on the right: "s[i] >= '0'"

	// Generators (Kukel v0.34).
	OpGenerator // return a generator that runs the rest of the function from the next instruction, a step at a time
	OpYield     // pop x: the generator's step ends, giving x; the next step goes on after it
	OpIterClose // slot u16: close the generator a for-each loop walks with the iterator in slot (nothing for others)
	OpGenReturn // the generator ends (its return; and the end of its body)

	// send and yield from (Kukel v0.37).
	OpYieldValue // pop x: as YIELD, and the next step goes on with the value sent to it (send; nil for next) pushed
	OpIterSend   // slot u16: pop x, the value the next step of the generator a for-each loop walks with the iterator in slot gets (yield from; dropped for others)

)

func (Op) Size

func (op Op) Size() int

Size returns the size in bytes of an instruction with opcode op.

func (Op) String

func (op Op) String() string

type OpInfo

type OpInfo struct {
	Name     string
	Operands []int // byte width of each operand
}

OpInfo describes an opcode for the disassembler and the loader.

func Info

func Info(op Op) (OpInfo, bool)

Info returns the description of op; ok is false for an unknown opcode.

type Program

type Program struct {
	Globals []Global
	Classes []*Class
	Funcs   []*Function
	Init    *Function
	Main    int // global index of main
}

Program is a compiled program: global slots, functions, an init function that runs the global initializers, and the entry point.

func Debuggable added in v0.15.0

func Debuggable(p *Program) *Program

Debuggable gives a copy of p for the debugger: every function has its own copy of its code, in which the first instruction of each source line is a BREAK (not where code continues a line: LineInfo.Cont); Function.Saved keeps the instruction it replaced. p itself does not change, and the copy runs as p does where no debug hook is set (the VM then runs the saved instruction at once).

func Decode

func Decode(data []byte) (*Program, error)

Decode reads a program written by Encode and verifies it (see Verify), so that running it cannot crash the VM.

type Upvalue

type Upvalue struct {
	Name      string // for the disassembler
	FromLocal bool
	Index     int // slot or upvalue index
}

Upvalue says where a closure gets a captured cell when it is made: from a slot of the function making it, or from that function's own upvalues.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL