bytecode

package
v0.1.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Sep 25, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package bytecode defines the moejs instruction set and the compiled-function template shared between the compiler and the engine's interpreter.

See doc.go for the ISA reference and opcodes.go for the encoding. The types in this file are the data model: nothing in a Function is mutated after compilation, so one *Function is shared by every realm (and every goroutine) that instantiates the same module. Per-realm state (inline caches, materialized constants) lives in engine side tables keyed by *Function.

Package bytecode: instruction set reference.

Machine model

moejs runs a register machine. A function executes in a window of NumRegs registers R[0..NumRegs-1] carved out of one contiguous per-realm value stack. Arguments arrive in R[0..argc-1]; missing parameters are undefined; when HasRest is set the surplus arguments are collected into an array in R[NumParams] before any other instruction runs, and when HasArguments is set an unmapped arguments object holding every argument is created in the next register (R[NumParams], or R[NumParams+1] after a rest array). `this` is held in the frame, not in a register. Registers above the parameters hold locals (un-captured let/const/var/function bindings) and expression temporaries; the compiler allocates them stack-like so that a call block (callee, this, args) is always the highest live group of registers.

Captured bindings never live in registers: they live in closure environments (Env). env^0 is the innermost environment; env^d is its d-th parent. A function whose CaptureLayout has n > 0 slots creates its own Env of n slots at entry (with the parameter registers listed in the layout copied in); otherwise it runs directly in the environment captured by its closure. Block scopes with captured bindings push and pop nested Envs.

Every instruction is one 32-bit word: op:8 | A:8 | B:8 | C:8, or op:8 | A:8 | Bx:16 (unsigned) / sBx:16 (signed). Ops marked +X below are followed by one ExtraArg word (a raw uint32); GetEnvChkW has two. Jump offsets are relative to the pc of the following word. Constants K[i] are Function.Consts; F[i] are Function.Children.

Exceptions unwind through Function.Handlers without panic/recover: the interpreter takes the first row whose [Start, End) covers the faulting pc, pops closure environments down to StackDepth, stores the thrown value as described by Kind, and resumes at Handler. Rows without a match propagate the error to the caller's frame. Interrupts (Realm.Interrupt) are checked at function entry and at every backward Jmp and are not catchable.

Opcodes

Loads and moves

LoadConst  A Bx        R[A] = K[Bx] (number, string or bigint constant)
LoadInt    A sBx       R[A] = sBx (small integer)
LoadUndef  A           R[A] = undefined
LoadNull   A           R[A] = null
LoadTrue   A           R[A] = true
LoadFalse  A           R[A] = false
LoadHole   A           R[A] = hole (the TDZ marker; never observable)
LoadThis   A           R[A] = this (undefined at module top level; lexical in arrows)
LoadCallee A           R[A] = the function object being executed (named function expressions)
Move       A B         R[A] = R[B]
UndefRange A B         R[A .. A+B-1] = undefined (var bindings at entry)

Closure environments

GetEnv     A B C       R[A] = env^B[C]
GetEnvChk  A B C +X    R[A] = env^B[C]; ReferenceError "K[X] is not defined" if hole
SetEnv     A B C       env^B[C] = R[A]
GetEnvW    A B +X      R[A] = env^B[X]              (slot >= 256)
GetEnvChkW A B +X +X   R[A] = env^B[X1] with TDZ check; X2 = name constant
SetEnvW    A B +X      env^B[X] = R[A]
PushEnv    Bx          env = new Env(env, Bx slots initialized to undefined)
PopEnv                 env = env.parent
CopyEnv                env = copy of env with the same parent (per-iteration let bindings)
CheckTDZ   A +X        ReferenceError "Cannot access 'K[X]' before initialization" if R[A] is hole

Globals (X = name constant:16 | inline cache:16)

GetGlobal        A +X  R[A] = globalThis[name]; ReferenceError if absent
GetGlobalOrUndef A +X  R[A] = globalThis[name] or undefined (typeof operand)
SetGlobal        A +X  globalThis[name] = R[A]; ReferenceError if absent (strict)

Properties

GetProp    A B +X      R[A] = R[B].name (X = name:16 | ic:16; TypeError on null/undefined base)
GetLen     A B +X      R[A] = R[B].length (array and string fast paths; X = ic in the high half)
SetProp    A B +X      R[A].name = R[B] (strict PutValue)
GetElem    A B C       R[A] = R[B][R[C]] (dense array and string index fast paths)
SetElem    A B C       R[A][R[B]] = R[C]
DelProp    A B +X      R[A] = delete R[B].name (strict: TypeError when not configurable)
DelElem    A B C       R[A] = delete R[B][R[C]]
In         A B C       R[A] = R[B] in R[C]
InstanceOf A B C       R[A] = R[B] instanceof R[C]

Literals

NewObject       A Bx   R[A] = {} (ordinary object, Bx = property count hint)
NewArray        A Bx   R[A] = [] (Bx = capacity hint)
DefineField     A B +X CreateDataProperty(R[A], K[name], R[B]) (X = name:16 | ic:16; the IC caches the shape transition)
DefineElem      A B C  CreateDataProperty(R[A], ToPropertyKey(R[B]), R[C])
DefineMethod    A B C  DefineElem for an object-literal method with a computed key: SetFunctionName(R[C], key) first
DefineAccessor  A B C +X  DefinePropertyOrThrow(R[A], ToPropertyKey(R[B]), {[[Get]] or [[Set]]: R[C], [[Enumerable]], [[Configurable]]: true}),
                       merging with an existing accessor half; X = AccessorSetter | AccessorEnumerable | AccessorNameKey
                       (AccessorNameKey: SetFunctionName(R[C], key, "get"/"set") first, for computed keys)
SetProto        A B    if R[B] is an object or null, R[A].[[Prototype]] = R[B] (the __proto__: v literal form)
CopyDataProps   A B    copy own enumerable properties of R[B] into R[A] (object spread)
CopyDataPropsEx A B C  same, skipping the keys listed in array R[C] (object rest pattern)
ArrayPush       A B    append R[B] to array R[A]
ArrayHole       A      append a hole to array R[A] (length += 1)
AppendSpread    A B    append every value produced by iterating R[B] to array R[A]
Closure         A Bx   R[A] = new function object over F[Bx] closing over env (and this for arrows)
NewRegExp       A Bx   R[A] = new RegExp(K[Bx].pattern, K[Bx].flags)
GetTemplate     A +X   R[A] = the template object of K[X lo] (GetTemplateObject: frozen cooked strings with a frozen raw array), created on the site's first evaluation in the realm and cached in IC slot X hi

Arithmetic (number fast paths; BigInt operands take the slow path)

Add       A B C        R[A] = R[B] + R[C] (numbers, string concatenation, ToPrimitive)
Sub       A B C        R[A] = R[B] - R[C]
Mul       A B C        R[A] = R[B] * R[C]
Div       A B C        R[A] = R[B] / R[C]
Mod       A B C        R[A] = R[B] % R[C]
Exp       A B C        R[A] = R[B] ** R[C]
AddImm    A B C        R[A] = R[B] + int8(C) (Add semantics: strings concatenate)
SubImm    A B C        R[A] = R[B] - int8(C)
Inc       A B          R[A] = ToNumeric(R[B]) + 1 (++; never concatenates)
Dec       A B          R[A] = ToNumeric(R[B]) - 1 (--)
Neg       A B          R[A] = -R[B]
Plus      A B          R[A] = +R[B] (ToNumber)
Not       A B          R[A] = !ToBoolean(R[B])
BitNot    A B          R[A] = ~R[B]
ToNumeric A B          R[A] = ToNumeric(R[B]) (postfix update result)
RequireObjectCoercible A  throw TypeError when R[A] is null or undefined (empty or rest-only destructuring pattern)
ToStr     A B          R[A] = ToString(R[B]) (template substitutions)
Concat    A B C        R[A] = R[B] + R[C], both already strings (rope above the threshold)
Typeof    A B          R[A] = typeof R[B]
TypeofIs  A B C        R[A] = typeof R[B] === TypeNames[C]
BitAnd    A B C        R[A] = R[B] & R[C]
BitOr     A B C        R[A] = R[B] | R[C]
BitXor    A B C        R[A] = R[B] ^ R[C]
Shl       A B C        R[A] = R[B] << R[C]
Shr       A B C        R[A] = R[B] >> R[C]
UShr      A B C        R[A] = R[B] >>> R[C]

Comparison

Eq       A B C         R[A] = R[B] == R[C]
Ne       A B C         R[A] = R[B] != R[C]
StrictEq A B C         R[A] = R[B] === R[C]
StrictNe A B C         R[A] = R[B] !== R[C]
Lt       A B C         R[A] = R[B] < R[C]
Le       A B C         R[A] = R[B] <= R[C]
Gt       A B C         R[A] = R[B] > R[C]
Ge       A B C         R[A] = R[B] >= R[C]

Control flow (offsets relative to the next pc)

Jmp           sBx      pc += sBx; a negative offset is a loop back-edge and checks the interrupt flag
JmpT          A sBx    if ToBoolean(R[A]) pc += sBx
JmpF          A sBx    if !ToBoolean(R[A]) pc += sBx
JmpNullish    A sBx    if R[A] is null or undefined pc += sBx
JmpNotNullish A sBx    if R[A] is neither null nor undefined pc += sBx
JmpNotUndef   A sBx    if R[A] is not undefined pc += sBx

Calls

Call       A B         R[A] = R[A](this = R[A+1], args R[A+2 .. A+1+B]); TypeError if not callable
CallSpread A           R[A] = R[A](this = R[A+1], ...array R[A+2])
New        A B         R[A] = new R[A](R[A+2 .. A+1+B]); TypeError if not a constructor
NewSpread  A           R[A] = new R[A](...array R[A+2])
Ret        A           return R[A]
RetUndef               return undefined
Throw      A           throw R[A]
ThrowConstAssign +X    throw TypeError("Assignment to constant variable.") (K[X] names the binding)

Iteration (for-of, spread and array destructuring share GetIterator and IteratorStepValue; R[A], R[A+1] hold the Iterator Record: the iterator and its next method, or, while the protocol is unobservable, the array or string itself and the next index; R[A] is undefined once done or closed)

IterInit  A B          R[A], R[A+1] = GetIterator(R[B]); TypeError if not iterable
IterNext  A sBx        R[A+2] = next value; when exhausted pc += sBx
IterValue A B          R[B] = next value or undefined when exhausted (destructuring)
IterRest  A B          R[B] = array of the remaining values (rest element)
IterClose A sBx        IteratorClose(R[A], normal completion) unless done; pc += sBx
IterThrow A B          IteratorClose(R[A], throw completion) unless done; throw R[B]
ForInInit A B          R[A] = enumerable string keys of R[B] (prototype chain, deduplicated), R[A+1] = 0, R[A+2] = the object
ForInNext A sBx        R[A+3] = next key still present as a property; when exhausted pc += sBx

Classes, super, new.target and private names (off the interpreter's jump table: they only run while classes are defined and in class code)

CtorEntry     A        R[A] = new.target; TypeError "Class constructor X cannot be invoked without 'new'" in a [[Call]] (first op of every class constructor)
LoadNewTarget A        R[A] = new.target, undefined in a [[Call]] (first op of a function with NewTarget set)
LoadHome      A        R[A] = [[HomeObject]] of the running function
SetHome       A B      [[HomeObject]] of function R[A] = R[B]
CreateClass   A B C    finish class constructor R[A] (the Closure of a class-constructor template):
                       R[A+1] = the new prototype object, R[A].prototype = R[A+1] (read-only),
                       R[A+1].constructor = R[A] (non-enumerable), [[HomeObject]] of R[A] = R[A+1];
                       C&1: R[B] is the heritage (null, or a constructor whose prototype is an object or null);
                       C&2: first name R[A] after property key R[A+1] (an anonymous class field value)
DefineClassMethod A B C  R[A][R[B]] := R[C] non-enumerable, [[HomeObject]] of R[C] = R[A];
                       an unnamed function is named after the key
ToPropertyKey A B      R[A] = ToPropertyKey(R[B]) (computed field keys)
GetProtoOf    A B      R[A] = R[B].[[GetPrototypeOf]]() or null: the super base of home object R[B],
                       or the super constructor of active function R[B]
GetSuper      A B C    R[A] = super property R[C] of base R[B] read with receiver R[B+1];
                       TypeError if the base is null (A may equal B)
SetSuper      A B C    set super property R[B] of base R[A] to R[C] with receiver R[A+1]; TypeError if refused
SuperCall     A B      R[A] = Construct(R[A], args R[A+2 .. A+1+B], new.target R[A+1]); TypeError if not a constructor
SuperCallSpread A      same with the argument array R[A+2] (AppendSpread-built, or the default constructor's rest array)
CheckSuper    A        ReferenceError "Super constructor may only be called once" unless R[A] is hole
DerivedResult A B      R[A] = the value a derived constructor returns for return value R[A] and raw `this` R[B]:
                       an object as is; undefined gives `this` (ReferenceError if still hole); otherwise TypeError
NewPrivateName A Bx    R[A] = a new private name described by K[Bx] ("#x", or the class name for a brand)
SetPrivateMethod A B C +X  make R[B] the method, getter or setter of private name R[A], checked against
                       the brand R[C] (or, with PrivateStatic, the class constructor R[C]); X = Private* flags
GetPrivate    A B C    R[A] = R[B].#R[C]; TypeError when R[B] lacks it
SetPrivate    A B C    R[A].#R[B] = R[C]; TypeError when R[A] lacks it or it is a method
DefPrivate    A B C    add private field #R[B] = R[C] to object R[A]; TypeError if already present
AddBrand      A B      add class brand R[B] to object R[A]; TypeError if already present
InPrivate     A B C    R[A] = #R[B] in R[C]; TypeError if R[C] is not an object
ThrowError    A Bx     throw a new TypeError (A=ThrowTypeError) or ReferenceError (A=ThrowReferenceError) with message K[Bx]

Index

Constants

View Source
const (
	TypeUndefined uint8 = iota
	TypeObject
	TypeBoolean
	TypeNumber
	TypeString
	TypeSymbol
	TypeBigInt
	TypeFunction
)

TypeName indices used by TypeofIs (operand C).

View Source
const (
	AccessorSetter     uint32 = 1 << iota // define the setter half (otherwise the getter)
	AccessorEnumerable                    // the property is enumerable
	AccessorNameKey                       // name the function "get <key>"/"set <key>" at run time (computed keys)
)

DefineAccessor flags (its ExtraArg word). Object literals set AccessorEnumerable; class accessors do not.

View Source
const (
	PrivateGetter uint32 = 1 << iota // the function is the getter of an accessor
	PrivateSetter                    // the function is the setter of an accessor
	PrivateStatic                    // checked against the class constructor instead of a brand
)

SetPrivateMethod flags (its ExtraArg word).

View Source
const (
	ThrowTypeError uint8 = iota
	ThrowReferenceError
)

ThrowError kinds (operand A).

View Source
const (
	MaxRegister = 255    // registers are 8-bit operands
	MaxBx       = 0xFFFF // unsigned 16-bit operand
	MaxSBx      = 0x7FFF
	MinSBx      = -0x8000
)

Instruction word layout constants.

View Source
const NoRegister uint16 = 0xFFFF

NoRegister marks a CaptureLayout slot that is not initialized from a parameter register.

View Source
const OpCount = int(opCount)

OpCount is the number of defined opcodes.

View Source
const UndefinedCooked = "\xff"

UndefinedCooked is the Const.Cooked entry of a tagged template chunk with an invalid escape, whose cooked value is undefined. The byte 0xFF never occurs in WTF-8.

Variables

View Source
var DescribeCallee func(f *Function, pc uint32) string

DescribeCallee, when non-nil, returns the source form of the callee of the Call, CallSpread, New or NewSpread instruction at pc of f ("obj.foo", "f(...)"), or "" when it cannot tell. Package compiler installs it; the engine calls it only to word the TypeError of a call or construction of a value that is not callable, so no call site carries any extra data.

View Source
var TypeNames = [typeNameCount]string{"undefined", "object", "boolean", "number", "string", "symbol", "bigint", "function"}

TypeNames spells the TypeofIs operand.

Functions

func DecodeA

func DecodeA(w uint32) uint8

DecodeA extracts operand A.

func DecodeB

func DecodeB(w uint32) uint8

DecodeB extracts operand B.

func DecodeBx

func DecodeBx(w uint32) uint16

DecodeBx extracts the unsigned 16-bit operand.

func DecodeC

func DecodeC(w uint32) uint8

DecodeC extracts operand C.

func DecodeSBx

func DecodeSBx(w uint32) int16

DecodeSBx extracts the signed 16-bit operand.

func Disassemble

func Disassemble(fn *Function) string

Disassemble renders fn (and, indented, its children) in a stable text form for tests and debugging.

func EncodeABC

func EncodeABC(op Op, a, b, c uint8) uint32

EncodeABC packs an ABC instruction.

func EncodeABx

func EncodeABx(op Op, a uint8, bx uint16) uint32

EncodeABx packs an ABx instruction.

func EncodeAsBx

func EncodeAsBx(op Op, a uint8, sbx int16) uint32

EncodeAsBx packs an AsBx instruction.

func ExtraArg

func ExtraArg(lo, hi uint16) uint32

ExtraArg packs two 16-bit fields (used for name:16 | ic:16).

func ExtraHi

func ExtraHi(x uint32) uint16

ExtraHi extracts the high half of an ExtraArg word.

func ExtraLo

func ExtraLo(x uint32) uint16

ExtraLo extracts the low half of an ExtraArg word.

func TypeNameIndex

func TypeNameIndex(name string) (uint8, bool)

TypeNameIndex returns the TypeofIs operand for a typeof result string.

Types

type CaptureLayout

type CaptureLayout []uint16

CaptureLayout describes the function's own closure environment: its length is the number of Env slots created at function entry (zero means the function creates no Env and runs in its closure's environment), and entry i is the parameter register whose value is boxed into slot i at entry, or NoRegister for slots initialized to undefined.

type Const

type Const struct {
	Kind    ConstKind
	Num     float64  // ConstNumber
	Str     string   // ConstString (WTF-8), ConstBigInt (decimal or 0x hex), ConstRegExp (pattern)
	IsASCII bool     // ConstString: every byte of Str is < 0x80
	Units   []uint16 // ConstString: UTF-16 code units when !IsASCII (nil otherwise)
	Key     bool     // ConstString: used as a property name (the engine interns it)
	Flags   string   // ConstRegExp flags
	Cooked  []string // ConstTemplate cooked strings (WTF-8, or UndefinedCooked)
	Raw     []string // ConstTemplate raw strings (UTF-8)
	Index   int      // ConstFunction: index into Function.Children
}

Const is a constant-pool entry. Only the fields relevant to Kind are set.

type ConstKind

type ConstKind uint8

ConstKind tags a constant-pool entry.

const (
	// ConstNumber is a float64 literal (Num).
	ConstNumber ConstKind = iota
	// ConstString is a string literal (Str, IsASCII, Units).
	ConstString
	// ConstBigInt is a BigInt literal stored as text (Str): decimal, or hex
	// after "0x" (see syntax.BigIntLit).
	ConstBigInt
	// ConstRegExp is a regular-expression literal (Str = pattern, Flags).
	ConstRegExp
	// ConstTemplate is a tagged template's strings (Cooked, Raw); untagged
	// templates are lowered to Concat.
	ConstTemplate
	// ConstFunction is an index into Function.Children (Index). Reserved;
	// Closure indexes Children directly.
	ConstFunction
)

type Format

type Format uint8

Format describes how an instruction's operands are laid out.

const (
	FmtNone Format = iota // no operands
	FmtA                  // A
	FmtAB                 // A B
	FmtABC                // A B C
	FmtABx                // A Bx
	FmtAsBx               // A sBx
	FmtSBx                // sBx
)

type Function

type Function struct {
	Name      string // "" for anonymous functions
	Length    int    // formal parameter count exposed as .length
	Strict    bool   // always true (strict mode only)
	Kind      Kind
	NumRegs   uint16 // register window size
	NumParams uint16 // declared parameters (excluding rest)
	HasRest   bool   // the rest array is collected into R[NumParams] at entry
	// HasArguments makes the entry create an unmapped arguments object in
	// the register after the parameters (and the rest array).
	HasArguments bool
	// NewTarget is set when the function reads new.target (LoadNewTarget):
	// [[Construct]] then passes it through the realm. Class constructors
	// always receive it.
	NewTarget bool
	// Generator marks a generator function (of kind KindMethod: not
	// constructible); its body starts with GenStart.
	Generator bool
	// Async marks an async function, async generator function or module
	// with top-level await (see compiler/async.go).
	Async bool
	// ICCount is the number of inline-cache slots this function needs. Their
	// indices are assigned per realm on the function's first call there
	// (engine.Realm.AllocIC); the template is never mutated.
	ICCount uint32

	Code     []uint32
	Consts   []Const
	Children []*Function
	Handlers []Handler

	CaptureLayout CaptureLayout
	LineTable     []LineEntry
	Source        *SourceInfo

	// Exports maps export names to module Env slots (KindModule only). The
	// module Env is the function's own Env, so every exported binding is a
	// CaptureLayout slot and GetBindingValue is one slice index.
	Exports map[string]int

	// Globals lists the names a script declares at top level (KindScript
	// only; nil when it declares none) for the checks of
	// GlobalDeclarationInstantiation before the body runs.
	Globals *GlobalNames
}

Function is an immutable compiled-function template. A single *Function is shared by every realm that instantiates the same module, so nothing in it may be mutated after compilation; per-realm state (inline caches) lives in engine.Realm side tables keyed by *Function.

func (*Function) Position

func (f *Function) Position(pc uint32) (line, col int)

Position returns the source line and column of the instruction at pc, or (0, 0) when the function has no line table.

func (*Function) SourceText

func (f *Function) SourceText() string

SourceText returns the function's source slice for Function.prototype.toString, or "" when unknown.

type GlobalNames

type GlobalNames struct {
	Lexical  []string // let, const and class names
	Function []string // function declaration names
	Var      []string // var names that are not also function names
}

GlobalNames are the top-level declarations of a script, each list in source order.

type Handler

type Handler struct {
	Start      uint32
	End        uint32
	Handler    uint32
	StackDepth uint16
	Kind       HandlerKind
	Reg        uint16 // register receiving the exception (see HandlerKind)
}

Handler is one exception-table row: [Start, End) is the protected pc range, Handler is the pc to resume at and StackDepth the closure-environment depth (number of PushEnv levels relative to function entry) to unwind to. Rows are ordered innermost first; the interpreter takes the first row whose range covers the faulting pc.

type HandlerKind

type HandlerKind uint8

HandlerKind distinguishes catch and finally rows of the handler table.

const (
	// HandlerCatch receives the thrown value in R[Reg].
	HandlerCatch HandlerKind = iota
	// HandlerFinally receives the completion kind (1 = throw) in R[Reg] and
	// the thrown value in R[Reg+1].
	HandlerFinally
)

type Kind

type Kind uint8

Kind classifies a compiled function template.

const (
	// KindNormal is an ordinary function declaration or expression.
	KindNormal Kind = iota
	// KindArrow is an arrow function (lexical this, not constructible).
	KindArrow
	// KindMethod is a concise object-literal method (not constructible).
	KindMethod
	// KindModule is the module top-level body.
	KindModule
	// KindScript is a strict-mode script top-level body (RunString).
	KindScript
	// KindClassCtor is a base class constructor: [[Construct]] creates
	// `this` from new.target and [[Call]] throws (CtorEntry). The class
	// kinds come last so IsClassCtor is one comparison.
	KindClassCtor
	// KindDerivedCtor is the constructor of a class with an extends clause:
	// `this` stays uninitialized until super() returns.
	KindDerivedCtor
)

func (Kind) IsClassCtor

func (k Kind) IsClassCtor() bool

IsClassCtor reports whether k is a class constructor kind.

func (Kind) String

func (k Kind) String() string

String returns the kind name used by disassembly and error messages.

type LineEntry

type LineEntry struct {
	PC   uint32
	Line int32
	Col  int32
}

LineEntry maps the first pc of a run of instructions to a source position.

type Op

type Op uint8

Op is an opcode. Opcodes are dense so that the interpreter's switch compiles to a jump table. See doc.go for the semantics of every op.

const (
	// --- loads and moves ---
	LoadConst  Op = iota // ABx  R[A] = K[Bx]
	LoadInt              // AsBx R[A] = sBx
	LoadUndef            // A    R[A] = undefined
	LoadNull             // A    R[A] = null
	LoadTrue             // A    R[A] = true
	LoadFalse            // A    R[A] = false
	LoadHole             // A    R[A] = hole (TDZ marker)
	LoadThis             // A    R[A] = this
	LoadCallee           // A    R[A] = the running function object
	Move                 // AB   R[A] = R[B]
	UndefRange           // AB   R[A .. A+B-1] = undefined

	// --- closure environments ---
	GetEnv     // ABC  R[A] = env^B[C]
	GetEnvChk  // ABC+X R[A] = env^B[C]; ReferenceError if hole; X = name const
	SetEnv     // ABC  env^B[C] = R[A]
	GetEnvW    // AB+X  R[A] = env^B[X]
	GetEnvChkW // AB+X+X R[A] = env^B[X1]; ReferenceError if hole; X2 = name const
	SetEnvW    // AB+X  env^B[X] = R[A]
	PushEnv    // ABx  env = new Env(parent env, Bx slots)
	PopEnv     // -    env = env.parent
	CopyEnv    // -    env = shallow copy of env (per-iteration bindings)
	CheckTDZ   // A+X  ReferenceError "Cannot access 'K[X]' before initialization" if R[A] is hole

	// --- globals ---
	GetGlobal        // A+X  R[A] = global[name]; ReferenceError if absent; X = name:16 | ic:16
	GetGlobalOrUndef // A+X  R[A] = global[name] or undefined (typeof)
	SetGlobal        // A+X  global[name] = R[A]; ReferenceError if absent

	// --- properties ---
	GetProp    // AB+X  R[A] = R[B].name;          X = name:16 | ic:16
	GetLen     // AB+X  R[A] = R[B].length;        X = ic:16
	SetProp    // AB+X  R[A].name = R[B];          X = name:16 | ic:16
	GetElem    // ABC   R[A] = R[B][R[C]]
	SetElem    // ABC   R[A][R[B]] = R[C]
	DelProp    // AB+X  R[A] = delete R[B].name;   X = name const
	DelElem    // ABC   R[A] = delete R[B][R[C]]
	In         // ABC   R[A] = R[B] in R[C]
	InstanceOf // ABC  R[A] = R[B] instanceof R[C]

	// --- literals ---
	NewObject       // ABx  R[A] = {} with room for Bx properties
	NewArray        // ABx  R[A] = [] with capacity Bx
	DefineField     // AB+X R[A].name := R[B] (CreateDataProperty); X = name const
	DefineElem      // ABC  R[A][R[B]] := R[C] (CreateDataProperty)
	DefineMethod    // ABC  R[A][R[B]] := R[C], naming the function R[C] after the key (computed-key method)
	DefineAccessor  // ABC+X define R[C] as the getter or setter of R[A][R[B]]; X = Accessor* flags
	SetProto        // AB   R[A].[[Prototype]] = R[B] when object or null (__proto__: v)
	CopyDataProps   // AB   copy own enumerable properties of R[B] into R[A]
	CopyDataPropsEx // ABC  same, excluding the keys listed in array R[C]
	ArrayPush       // AB   append R[B] to array R[A]
	ArrayHole       // A    append a hole to array R[A]
	AppendSpread    // AB   append every element of iterable R[B] to array R[A]
	Closure         // ABx  R[A] = new function object from Children[Bx]
	NewRegExp       // ABx  R[A] = new RegExp(K[Bx].pattern, K[Bx].flags)
	GetTemplate     // A+X  R[A] = template object of K[X] (GetTemplateObject); X = const:16 | ic:16

	// --- arithmetic ---
	Add       // ABC  R[A] = R[B] + R[C]
	Sub       // ABC
	Mul       // ABC
	Div       // ABC
	Mod       // ABC
	Exp       // ABC  R[A] = R[B] ** R[C]
	AddImm    // ABC  R[A] = R[B] + int8(C)
	SubImm    // ABC  R[A] = R[B] - int8(C)
	Inc       // AB   R[A] = ToNumeric(R[B]) + 1
	Dec       // AB   R[A] = ToNumeric(R[B]) - 1
	Neg       // AB   R[A] = -R[B]
	Plus      // AB   R[A] = +R[B] (ToNumber)
	Not       // AB   R[A] = !R[B]
	BitNot    // AB   R[A] = ~R[B]
	ToNumeric // AB   R[A] = ToNumeric(R[B])
	// RequireObjectCoercible throws TypeError when R[A] is null or undefined
	// (destructuring through a pattern with no properties to read).
	RequireObjectCoercible // A
	ToStr                  // AB   R[A] = ToString(R[B])
	Concat                 // ABC  R[A] = R[B] concatenated with R[C] (both strings)
	Typeof                 // AB   R[A] = typeof R[B]
	TypeofIs               // ABC  R[A] = typeof R[B] === TypeName(C)
	BitAnd                 // ABC
	BitOr                  // ABC
	BitXor                 // ABC
	Shl                    // ABC
	Shr                    // ABC  signed >>
	UShr                   // ABC  >>>

	// --- comparison ---
	Eq       // ABC  R[A] = R[B] == R[C]
	Ne       // ABC
	StrictEq // ABC
	StrictNe // ABC
	Lt       // ABC
	Le       // ABC
	Gt       // ABC
	Ge       // ABC

	// --- control flow ---
	Jmp           // sBx   pc += sBx  (negative offsets are back-edges: interrupt check)
	JmpT          // AsBx  if ToBoolean(R[A]) pc += sBx
	JmpF          // AsBx  if !ToBoolean(R[A]) pc += sBx
	JmpNullish    // AsBx  if R[A] is null or undefined
	JmpNotNullish // AsBx
	JmpNotUndef   // AsBx

	// --- calls ---
	Call             // AB   R[A] = R[A].call(this = R[A+1], R[A+2 .. A+1+B])
	CallSpread       // A    R[A] = R[A].call(this = R[A+1], ...R[A+2])
	New              // AB   R[A] = new R[A](R[A+2 .. A+1+B])
	NewSpread        // A    R[A] = new R[A](...R[A+2])
	Ret              // A    return R[A]
	RetUndef         // -    return undefined
	Throw            // A    throw R[A]
	ThrowConstAssign // +X  throw TypeError("Assignment to constant variable."); X = name const

	// --- iteration ---
	IterInit  // AB    R[A], R[A+1] = iterator state over R[B]
	IterNext  // AsBx  R[A+2] = next value of iterator R[A]; when done pc += sBx
	IterValue // AB    R[B] = next value of iterator R[A], or undefined when done
	IterRest  // AB    R[B] = array of the remaining values of iterator R[A]
	IterClose // AsBx  IteratorClose(R[A], normal); pc += sBx
	IterThrow // AB    IteratorClose(R[A], throw R[B]); throw R[B]
	ForInInit // AB    R[A] = key list of R[B], R[A+1] = 0, R[A+2] = ToObject(R[B]) (or undefined)
	ForInNext // AsBx  R[A+3] = next key still present on R[A+2]; when done pc += sBx

	// --- classes (dispatched off the interpreter's jump table) ---
	CtorEntry         // A     R[A] = new.target; TypeError when a class constructor is called
	LoadNewTarget     // A     R[A] = new.target, or undefined in a [[Call]]
	LoadHome          // A     R[A] = [[HomeObject]] of the running function
	SetHome           // AB    [[HomeObject]] of function R[A] = R[B]
	CreateClass       // ABC   make R[A] a class constructor, R[A+1] = its prototype; C&1: R[B] is the heritage, C&2: named after key R[A+1]
	DefineClassMethod // ABC   R[A][R[B]] := R[C] non-enumerable, [[HomeObject]] R[A]
	ToPropertyKey     // AB    R[A] = ToPropertyKey(R[B])
	GetProtoOf        // AB    R[A] = R[B].[[GetPrototypeOf]]() (super base, super constructor)
	GetSuper          // ABC   R[A] = R[B][R[C]] with receiver R[B+1]
	SetSuper          // ABC   R[A][R[B]] = R[C] with receiver R[A+1]
	SuperCall         // AB    R[A] = Construct(R[A], R[A+2 .. A+1+B], new.target R[A+1])
	SuperCallSpread   // A     R[A] = Construct(R[A], ...R[A+2], new.target R[A+1])
	CheckSuper        // A     ReferenceError unless R[A] (the raw `this` binding) is hole
	DerivedResult     // AB    R[A] = result of a derived constructor returning R[A] with `this` R[B]
	NewPrivateName    // ABx   R[A] = new private name described by K[Bx]
	SetPrivateMethod  // ABC+X private name R[A] names method R[B] owned by brand/class R[C]; X = Private* flags
	GetPrivate        // ABC   R[A] = R[B].#R[C]
	SetPrivate        // ABC   R[A].#R[B] = R[C]
	DefPrivate        // ABC   add private field #R[B] = R[C] to R[A]
	AddBrand          // AB    add class brand R[B] to R[A]
	InPrivate         // ABC   R[A] = #R[B] in R[C]
	ThrowError        // ABx   throw a new error of kind A (Throw* kinds) with message K[Bx]

	// --- generators (dispatched off the jump table after the class ops) ---
	GenFunc  // A     make the fresh closure R[A] a generator function
	GenStart // A     R[A] = new generator with `this` R[A]; suspends it, and the call returns it
	Yield    // ABC   generator R[B] suspends yielding R[A] (C=1: R[A] is a result object, yielded as is);
	//                 resumed with the sent value in R[A] and the mode in R[A+1]: undefined next, true throw, false return
	GenIter  // AB    R[A] = GetIterator(R[B]) (never a fast mode), R[A+1] = its next method
	Delegate // AB    one yield* step on the record R[B..B+1] with the value R[A] and mode R[A+1] (as Yield):

	// --- async functions and iteration (dispatched after the generator ops) ---
	AsyncFunc       // A     make the fresh closure R[A] an async function or async generator function
	AsyncStart      // A     R[A] = the state of an async function call with `this` R[A]; the call returns its promise
	AsyncGenStart   // A     R[A] = new async generator with `this` R[A]; suspends it, and the call returns it
	Await           // AB    R[B] (the async state) awaits R[A]; resumed with R[A] = the result, R[A+1] = undefined (fulfilled) or true (rejected)
	AsyncReturn     // AB    resolve the promise of async function R[B] with R[A]; R[A] = the promise
	AsyncThrow      // AB    reject the promise of async function R[B] with R[A]; R[A] = the promise
	AsyncYield      // AB    async generator R[B] settles its head request with {value: R[A], done: false}; resumed as Yield
	AsyncIterInit   // AB    R[A] = GetIterator(R[B], async), R[A+1] = its next method
	AsyncIterNext   // A     R[A+2] = Call(R[A+1], R[A])
	AsyncIterResult // AsBx  TypeError unless R[A+2] is an object; when done pc += sBx, else R[A+2] = its value
	AsyncIterClose  // AsBx  R[A] = undefined; pc += sBx if the iterator has no return method, else R[A+2] = Call(return, iterator)
	AsyncIterClosed // A     TypeError unless the awaited return result R[A+2] is an object
	AsyncDelegate   // ABC   one async yield* step on the record R[B..B+2] with value R[A] and mode R[A+1] (C=0 call, C=1 result)

)

Instruction formats. Every instruction is one 32-bit word:

ABC : op:8 | A:8 | B:8 | C:8
ABx : op:8 | A:8 | Bx:16        (Bx unsigned)
AsBx: op:8 | A:8 | sBx:16       (sBx signed, jump offset relative to the next pc)

Ops marked "+X" in doc.go are followed by one ExtraArg word (a raw uint32) whose layout is given per op; a few use two.

func DecodeOp

func DecodeOp(w uint32) Op

DecodeOp extracts the opcode.

func (Op) ExtraWords

func (op Op) ExtraWords() int

ExtraWords returns how many ExtraArg words follow an instruction of op.

func (Op) Format

func (op Op) Format() Format

Format returns the operand layout of op.

func (Op) String

func (op Op) String() string

String returns the mnemonic.

type SourceInfo

type SourceInfo struct {
	Name  string // file name used in stack traces
	Src   string // full module/script source text
	Start int    // byte offset of the function's first character
	End   int    // byte offset one past the function's last character
}

SourceInfo locates a function template inside its source file. Function.prototype.toString slices Src[Start:End].

Jump to

Keyboard shortcuts

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