vm

package
v0.33.1 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package vm executes compiled Kukel programs on a stack machine.

Each call has a frame. A frame's slots (parameters, locals, hidden slots) sit on the value stack at frame.base, followed by its operand stack. The callee value sits just below the slots.

Index

Constants

View Source
const MaxFrames = 10000

MaxFrames bounds the call depth; deeper recursion is a stack overflow.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builtins

type Builtins func(name string) (*value.BuiltinObj, bool)

Builtins resolves built-in functions by name.

type Calls added in v0.30.0

type Calls struct {
	Interp string
	Func   *bytecode.Function
	Go     string
}

Calls names what a call count counts: the calls in interpreter Interp of Kukel function Func, or (Func nil) of the built-in or Go function Go.

type Canceller added in v0.2.0

type Canceller struct {
	// contains filtered or unexported fields
}

Canceller stops a running program from another goroutine. Cancellers form a tree: cancelling one cancels the ones made from it (Child).

func NewCanceller added in v0.2.1

func NewCanceller() *Canceller

NewCanceller makes a Canceller that nothing has cancelled yet.

func (*Canceller) Cancel added in v0.2.0

func (c *Canceller) Cancel(reason error)

Cancel makes the programs that use c (and its children) stop at their next step with a CancelledError that try cannot catch; Go functions that wait (sleep, receive) return at once. It may be called from any goroutine, and more than once.

func (*Canceller) Child added in v0.2.1

func (c *Canceller) Child() *Canceller

Child makes a Canceller that is cancelled when c is (at once if c already is).

func (*Canceller) Keep added in v0.2.1

func (c *Canceller) Keep()

Keep marks c as used by a worker (see Release).

func (*Canceller) Release added in v0.2.1

func (c *Canceller) Release(child *Canceller)

Release forgets child (made by Child) when it is no longer needed, unless workers use it: they must still be cancelled with c.

type DebugFrame added in v0.15.0

type DebugFrame struct {
	Func *bytecode.Function
	Line int              // the line it is at (where it called the next frame)
	This *value.ObjectObj // the object of a member function call, or nil
	PC   int              // the instruction it is at (of the call, for a caller)
}

DebugFrame is a call the program is in, for the debugger.

type DebugVar added in v0.15.0

type DebugVar struct {
	Name  string
	Value value.Value
}

DebugVar is a variable of a frame: a parameter, local or captured one.

type Node added in v0.31.0

type Node struct {
	Parent int
	Interp string
	Func   *bytecode.Function
	Line   int
	Time   time.Duration
	Count  int64
}

Node is a node of the call tree of the samples: the function Func at line Line, called from node Parent (an index into the nodes). A root (Parent -1, Func nil) is an interpreter. Time and Count are of the samples whose stack ended at the node.

type ProfFrame added in v0.30.0

type ProfFrame struct {
	Func *bytecode.Function
	Line int
}

ProfFrame is a function of a sampled stack and the line it was at.

type ProfileSummary added in v0.31.0

type ProfileSummary struct {
	Total    time.Duration // the time of the samples
	Elapsed  time.Duration // the wall time they cover (with CPU, also what was left out)
	Samples  int64
	Interps  []string      // the interpreters profiled, in the order they started
	Running  []string      // those that run: their calls are counted up to their latest sample
	Start    time.Time     // when the first interpreter started (zero: none did)
	Duration time.Duration // from Start to when the last one stopped (or now, while one runs)
}

ProfileSummary sums up what a Profiler collected.

type Profiler added in v0.30.0

type Profiler struct {
	Interval time.Duration // between samples (0 or less: 1 ms)
	CPU      bool          // leave out the time spent waiting in Go functions (see VM.WaitStart)
	// contains filtered or unexported fields
}

Profiler collects the samples and call counts of the interpreters it profiles: a program and its workers. Its methods are safe for concurrent use.

func NewProfiler added in v0.30.0

func NewProfiler(interval time.Duration, cpu bool) *Profiler

NewProfiler makes a Profiler.

func (*Profiler) Calls added in v0.30.0

func (p *Profiler) Calls() map[Calls]int64

Calls gives the call counts: exact for the interpreters that stopped (or paused), up to their latest sample for those that run.

func (*Profiler) Samples added in v0.30.0

func (p *Profiler) Samples() []Sample

Samples gives the stacks of the samples so far (from the call tree).

func (*Profiler) Summary added in v0.31.0

func (p *Profiler) Summary() ProfileSummary

Summary sums up what p collected so far.

func (*Profiler) Tree added in v0.31.0

func (p *Profiler) Tree() []Node

Tree gives the call tree of the samples so far: each node after its parent.

func (*Profiler) WorkerName added in v0.30.0

func (p *Profiler) WorkerName(fn string) string

WorkerName names a new worker that runs fn: "worker 1: f".

type RuntimeError

type RuntimeError struct {
	Value value.Value  // the thrown Error object (nil for the step limit, cancellation, exit)
	Kind  string       // its kind (never "": an empty kind becomes the class name)
	Msg   string       // its message ("" without one)
	Trace []TraceEntry // innermost call first
	Fatal bool         // try cannot catch it (exit, the step limit, cancellation)
	Exit  *int         // set by exit(code): not an error, the program ends
}

RuntimeError is a thrown exception: the thrown value and the stack trace at the throw. It is what Run returns for an exception nobody caught.

func (*RuntimeError) Error

func (e *RuntimeError) Error() string

Error returns the message and the stack trace. Long traces (deep recursion) show only the first and last traceEnds calls.

type Sample added in v0.30.0

type Sample struct {
	Interp string
	Stack  []ProfFrame
	Time   time.Duration
	Count  int64
}

Sample is the time of one call stack: the interpreter (as Interp names it), its frames outermost first, and the time (and the number of samples) that ended there.

type TraceEntry

type TraceEntry struct {
	Func string
	File string
	Line int
}

TraceEntry is one line of a stack trace.

type VM

type VM struct {

	// StepLimit, when positive, stops the program with a fatal error after
	// that many backward jumps, calls of Kukel functions and thrown
	// exceptions: for tests, and for Go programs that run untrusted code
	// (the kukel package resets the count for every call from Go).
	StepLimit int

	// Debug, when set, runs at every BREAK instruction: at the start of each
	// source line of code that the debugger made a copy of (Debuggable).
	// The VM's frames are then as at the start of that line (Frames). An
	// error stops the program (a fatal one, such as exit, ends it).
	Debug func(vm *VM) error

	// DebugUncaught, when set, runs when an exception is thrown that no
	// try of the program catches (a finally does not count), before the
	// frames are dropped (Frames). An error it gives ends the program
	// instead (a fatal one, such as exit).
	DebugUncaught func(vm *VM, re *RuntimeError) error
	// contains filtered or unexported fields
}

VM runs one program.

func New

func New(prog *bytecode.Program, builtins Builtins, stdout io.Writer, stdin io.Reader) (*VM, error)

New prepares prog for running: it binds the functions and built-ins to their global slots.

func NewWith added in v0.2.0

func NewWith(prog *bytecode.Program, builtins Builtins, config *native.Config, stdout io.Writer, stdin io.Reader) (*VM, error)

NewWith is New for a program limited by config (see native.Config): it refuses a program that uses a built-in or module config does not allow.

func (*VM) BuiltinLookup added in v0.2.0

func (vm *VM) BuiltinLookup() Builtins

BuiltinLookup is how the VM found its built-ins (New's builtins).

func (*VM) Call

func (vm *VM) Call(fn value.Value, args []value.Value) (value.Value, error)

Call calls fn from a built-in (sort's comparator, for example). The built-in's own arguments stay on the stack below the new call.

func (*VM) Cancellable added in v0.2.0

func (vm *VM) Cancellable() *Canceller

Cancellable makes the program cancellable from now on with the returned Canceller (replacing an earlier one). Workers started afterwards share it: cancelling the program cancels them too.

func (*VM) CloseOutput added in v0.2.1

func (vm *VM) CloseOutput()

CloseOutput flushes the output shared with workers (ShareOutput) and drops what they write later. Run does it when main returns.

func (*VM) Config added in v0.2.0

func (vm *VM) Config() *native.Config

Config is what the program may use (nil: everything).

func (*VM) CurrentCanceller added in v0.2.0

func (vm *VM) CurrentCanceller() *Canceller

CurrentCanceller is the VM's Canceller, or nil.

func (*VM) Done added in v0.2.0

func (vm *VM) Done() <-chan struct{}

Done implements value.Env: closed when the program is cancelled (nil if it cannot be).

func (*VM) Err added in v0.2.0

func (vm *VM) Err() error

Err implements value.Env: the error for a cancelled program, else nil.

func (*VM) Extend added in v0.7.0

func (vm *VM) Extend(prog *bytecode.Program) error

Extend continues with prog, a program that adds to the VM's program (compiler.Session): globals, classes and functions after the ones the VM has, and member functions defined since for the classes it has. The values of the globals stay.

func (*VM) FlushOutput added in v0.31.0

func (vm *VM) FlushOutput() error

FlushOutput flushes the program's standard output if it is buffered (as eprint does), also while workers write to it: for a debugger, before it shows something.

func (*VM) Frames added in v0.15.0

func (vm *VM) Frames() []DebugFrame

Frames gives the calls the program is in, outermost first; the last is the one at the BREAK the debug hook was called for.

func (*VM) Global added in v0.2.0

func (vm *VM) Global(name string) (value.Value, bool)

Global returns the value of the global called name: a top-level name of the program ("main"), or a module's ("util::f", "json::encode").

func (*VM) Globals added in v0.28.0

func (vm *VM) Globals() []string

Globals gives the names of the program's global variables (not its functions and classes), in the order of the program.

func (*VM) Init added in v0.2.0

func (vm *VM) Init() error

Init runs the global initializers, the first time only. If they throw an exception, every later Init gives the same error: the globals are not usable. If the step limit or a cancellation stopped them, the next Init runs them again from the start.

func (*VM) Local added in v0.2.0

func (vm *VM) Local(key any, init func() any) any

Local implements value.Env.

func (*VM) PauseProfile added in v0.31.0

func (vm *VM) PauseProfile()

PauseProfile stops profiling vm until ResumeProfile: for the Go API, whose calls are profiled but not the time between them. The call counts go to the Profiler. It is called on vm's goroutine.

func (*VM) Profiler added in v0.30.0

func (vm *VM) Profiler() *Profiler

Profiler is the Profiler of vm, or nil.

func (*VM) Program added in v0.2.0

func (vm *VM) Program() *bytecode.Program

Program is the program the VM runs.

func (*VM) Rand

func (vm *VM) Rand() *rand.Rand

func (*VM) ResetSteps added in v0.2.0

func (vm *VM) ResetSteps()

ResetSteps starts counting steps for StepLimit from zero again.

func (*VM) ResumeProfile added in v0.31.0

func (vm *VM) ResumeProfile()

ResumeProfile goes on profiling vm after PauseProfile.

func (*VM) Run

func (vm *VM) Run(args []string) (int, error)

Run runs the global initializers, then main(args). It returns main's result as the exit code (an int result; anything else is 0).

When main returns, the program ends: if workers share the output (ShareOutput), it is flushed and closed, so that workers still running cannot write any more.

func (*VM) SetGlobal added in v0.28.0

func (vm *VM) SetGlobal(name string, v value.Value) bool

SetGlobal gives the global variable called name (as Global names it) the value v, and reports whether there is one; functions and classes cannot be changed.

func (*VM) SetStderr

func (vm *VM) SetStderr(w io.Writer)

SetStderr sets where eprint writes.

func (*VM) SetVar added in v0.28.0

func (vm *VM) SetVar(i int, name string, v value.Value) bool

SetVar gives the variable name of frame i (as Vars names it; of two with that name, the later one) the value v, and reports whether there is one.

func (*VM) ShareCanceller added in v0.2.0

func (vm *VM) ShareCanceller(c *Canceller)

ShareCanceller makes vm stop when c is cancelled (for a worker).

func (*VM) ShareOutput added in v0.2.0

func (vm *VM) ShareOutput() (stdout, stderr io.Writer)

ShareOutput makes the VM's standard output and error safe to use from several goroutines (workers) and returns them; other VMs can write to them too. Calling it again gives the same writers.

func (*VM) Start added in v0.2.0

func (vm *VM) Start(fn value.Value, args []value.Value) (value.Value, error)

Start runs the global initializers, then calls fn(args...) and gives its result. With fn nil it calls main, with args[0] as its parameter if main has one. exit(code) gives a *RuntimeError with Exit set.

func (*VM) StartProfile added in v0.30.0

func (vm *VM) StartProfile(p *Profiler, interp string)

StartProfile profiles vm with p from now on, under the name interp, until StopProfile (PauseProfile and ResumeProfile leave out the time between).

func (*VM) Started

func (vm *VM) Started() time.Time

func (*VM) Stderr

func (vm *VM) Stderr() io.Writer

func (*VM) Stdin

func (vm *VM) Stdin() *bufio.Reader

func (*VM) Stdout

func (vm *VM) Stdout() io.Writer

Stdout, Stderr, Stdin, Call, Rand, Started, Local, Thrown, Done and Err implement value.Env for the built-ins and the native modules.

func (*VM) StopProfile added in v0.30.0

func (vm *VM) StopProfile()

StopProfile ends the profiling of vm, and gives its call counts to the Profiler. It is called on vm's goroutine, after it ran.

func (*VM) Thrown added in v0.2.0

func (vm *VM) Thrown(err error) (value.Value, bool)

Thrown implements value.Env.

func (*VM) Vars added in v0.15.0

func (vm *VM) Vars(i int) []DebugVar

Vars gives the variables of frame i (an index into Frames), outer scopes first: the captured variables, then the parameters and locals in scope where it is, by their slots. Of two with the same name, the later one is the one the code sees. A function without Locals (from a .kkc file) gives all its slots by SlotNames (a slot that two blocks share has both names).

func (*VM) WaitEnd added in v0.31.0

func (vm *VM) WaitEnd(start time.Time)

WaitEnd tells the VM that the wait WaitStart gave start for ended: with CPU, the next sample leaves its time out.

func (*VM) WaitStart added in v0.31.0

func (vm *VM) WaitStart() time.Time

WaitStart tells the VM that a Go function it called begins to wait (for time, a message, an event, input): see native.Wait. It gives the time for WaitEnd, or the zero time when the VM does not need it (it is not profiled with CPU). It is called on vm's goroutine.

Jump to

Keyboard shortcuts

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