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
- func Disassemble(w io.Writer, p *Program) error
- func Encode(p *Program) ([]byte, error)
- func ReadU16(code []byte, at int) int
- func ReadU32(code []byte, at int) int
- func StackUse(op Op, operands []int) (pops, pushes int)
- func Verify(p *Program) error
- type Class
- type Function
- type Global
- type GlobalKind
- type LineInfo
- type Method
- type Op
- type OpInfo
- type Program
- type Upvalue
Constants ¶
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).
const FormatVersion = 2 // 2: milestone 12 superinstructions
FormatVersion is the version of the .kkc format written by Encode.
Variables ¶
This section is empty.
Functions ¶
func Disassemble ¶
Disassemble writes a readable listing of the program.
func StackUse ¶
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 ¶
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
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 + temporaries + 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
Upvalues []Upvalue // a function literal's captured variables
NumCaches int // inline cache slots of member instructions (the VM keeps the caches)
// 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) ParamSlots ¶
ParamSlots is the number of slots that hold parameters.
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] )
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 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 a value and throw it 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-- )