bytecode

package
v0.1.0-alpha.4 Latest Latest
Warning

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

Go to latest
Published: Oct 5, 2026 License: Apache-2.0 Imports: 5 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 (but for the name index an EvalLevel caches, see EvalLevel.Slot), 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 and GetImportW have 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

Module imports (env^B[C] holds a reference to the exporting module's binding, filled in when the module graph is instantiated)

GetImport  A B C +X    R[A] = the binding env^B[C] refers to; ReferenceError if hole; X = name constant
GetImportW A B +X +X   same with slot X1 (slot >= 256); X2 = name constant

Dynamic import and import.meta (off the interpreter's jump table, after the async ops; the compiler sets Function.ScriptOrModule on the root of code that uses them, and of a script or module holding a direct eval)

ImportCall A B         R[A] = a new promise for import(R[B]): ToString(R[B]), then the host's module for
                       it in the running root's script or module, linked and evaluated in the realm's module
                       map, fulfils it with the module's namespace; any failure rejects it
ImportMeta A           R[A] = import.meta of the running root module: a null-prototype object created, and
                       filled by the host, on the first read in the realm

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)

A global name resolves first in the realm's global declarative environment (the let, const and class declarations of scripts), then on the global object. Scripts reach their own top-level declarations by name too: GlobalDeclarationInstantiation (Realm.RunScript) creates them from Function.Extra.Globals before the body runs.

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)
GetElemRef A B C +X    R[C] = the key R[X], converted by ToPropertyKey when it is an object and
                       the base R[B] is neither undefined nor null; then GetElem A B C: the read of a
                       compound assignment or update, whose key GetValue converts once, after ToObject
                       of the base, and PutValue reuses (X is a register, C or another)
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]

Sloppy mode, script globals and with (off the interpreter's jump table, after the async ops: only sloppy code, script top levels, with statements and strict assignments of an undeclared name from a value that may run code use them)

SetGlobalSloppy A +X   PutValue of an identifier resolved against the global environment in sloppy code:
                       an unresolvable name becomes a global object property; a rejected write is
                       ignored (X = name:16 | ic:16, the SetGlobal cache)
ResolveGlobal A +X     R[A] = HasBinding(K[X.lo]) of the global environment: ResolveBinding of an
                       undeclared name in strict code, before the value assigned to it (X = name:16 | ic:16)
SetGlobalRef  A B +X   PutValue of R[A] to the reference ResolveGlobal resolved: ReferenceError unless
                       R[B] (its result) is true, else SetMutableBinding(K[X.lo], R[A], strict), whose
                       HasProperty throws a ReferenceError for a binding gone since (X = ResolveGlobal's)
InitGlobal    A +X     initialize the script's global lexical binding K[X.lo] to R[A] (X.hi = 1: const)
SetGlobalVar  A +X     evaluation of a sloppy block function declaration at script level (Annex B.3.2.2):
                       globalThis[K[X]] = R[A] as SetGlobalSloppy, skipped when a global lexical binding K[X] exists
DelGlobal     A +X     R[A] = delete K[X] for a name resolved against the global environment:
                       false for a global lexical binding, else globalThis.[[Delete]](K[X])
SetPropSloppy A B +X   R[A].name = R[B], ignoring a rejected assignment (X = name:16 | ic:16)
SetElemSloppy A B C    R[A][R[B]] = R[C], ignoring a rejected assignment
DelPropSloppy A B +X   R[A] = delete R[B].name; false instead of a TypeError when not configurable
DelElemSloppy A B C    R[A] = delete R[B][R[C]]; false instead of a TypeError when not configurable
SetSuperSloppy A B C   set super property R[B] of base R[A] to R[C] with receiver R[A+1], ignoring a
                       rejected assignment
ToObject      A B      R[A] = ToObject(R[B]); TypeError on null or undefined
JmpWith       A sBx +X pc += sBx if the object environment of with object R[A] has binding K[X]:
                       HasProperty, then a truthy @@unscopables entry blocks it; falls through when R[A]
                       is not an object (a function's %evalvars before a direct eval declares a var)
WithGet       A B +X   R[A] = GetBindingValue(K[X.lo]) of the object environment of R[B]: undefined,
                       or with X.hi = 1 (strict) a ReferenceError, when the property is gone
WithSet       A B +X   SetMutableBinding(K[X.lo], R[B]) of the object environment of R[A]
                       (X.hi = 1: strict, a ReferenceError when the property is gone and a TypeError when rejected)
CoerceThis             this = the global object when undefined or null, else ToObject(this)
                       (the entry of a sloppy function that uses this)
MapArguments  A        make the fresh arguments object R[A] a mapped one: its indices below both the argument
                       count and NumParams alias the parameters' slots of the function's own Env (CaptureLayout
                       entries below NumParams) and callee is the running function
CallEval      A B C +X R[A] = Call as with Call (C = 1: CallSpread) of callee R[A], this R[A+1]; when the
                       callee is the realm's %eval% it is a direct eval (PerformEval) of the first argument
                       in the running Env, compiled against the call site's scope Extra.Evals[X]

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 EvalLevel

type EvalLevel struct {
	Kind  uint8 // syntax.ScopeKind of the scope owning the Env
	Names []string
	Kinds []uint8
	TDZ   []bool
	// Outer is the next Env up the chain, nil for the outermost.
	Outer *EvalLevel
	// contains filtered or unexported fields
}

EvalLevel is one Env of an EvalScope: its binding names in slot order ("" for a slot no binding owns), with the syntax.BindKind and whether the binding has a temporal dead zone for each.

func (*EvalLevel) Slot

func (l *EvalLevel) Slot(name string) int

Slot returns the slot of the binding named name, or -1 when the Env has none. A large level indexes its names on first use, so that eval code using a few of them does not pay for all: the index is a cache every goroutine would build the same, stored atomically, and the one thing written to a Function after compilation.

type EvalScope

type EvalScope struct {
	// Env is the level of the running Env of the call site, nil when there
	// is none; its Outer chain are the Envs outwards: level i is the Env i
	// hops up the chain from the running Env. The script's global bindings
	// are not levels; they are resolved through the global object and the
	// global lexical environment.
	Env *EvalLevel
	// Var is the level holding the variable environment of the calling
	// function (its %evalvars object), or -1 for the global one.
	Var int
	// This is the level of the Env of the function supplying this,
	// new.target and super (the nearest non-arrow function), or -1 when
	// the call site is not inside a function.
	This int
	// Fields is the level holding the %fields binding of the class of a
	// derived constructor supplying this (super() in the eval code runs its
	// field initializers), or -1.
	Fields int
	// FuncKind is the syntax.FuncKind of that function and Derived marks a
	// derived class constructor.
	FuncKind uint8
	Derived  bool
	// Strict is the strictness of the calling code; InParams marks a call
	// in the parameter list of a function whose body has its own variable
	// environment; Module marks a call in module code.
	Strict, InParams, Module bool
}

EvalScope describes the environment chain visible at a direct eval call site so that the compiler can resolve the eval code against it at run time. It is opaque to the engine, which hands it to the compile hook together with the source text. The call sites of a compilation share their EvalScopes and EvalLevels where they can: sites in one scope have the same EvalScope, and the chains of sites in nested scopes share their outer levels.

type Export

type Export struct {
	Name string
	Slot int
}

Export is a local export: a name and the Env slot of its binding.

type Extra

type Extra struct {
	// Globals lists the names a script or global eval code declares at top
	// level (nil when it declares none) for GlobalDeclarationInstantiation
	// or EvalDeclarationInstantiation, which check and create them before
	// the body runs.
	Globals *GlobalNames
	// Evals describes the scope of each direct eval call site (CallEval's
	// X operand indexes it).
	Evals []*EvalScope
}

Extra is the rarely needed part of a Function.

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   // strict mode code (modules, classes, "use strict"); else sloppy
	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); the prologue
	// of a sloppy function with simple parameters maps it (MapArguments).
	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
	// ScriptOrModule is set on the root template of a script or module
	// whose code uses import() or import.meta: they need the script or
	// module record the host gave for it at run time
	// (GetActiveScriptOrModule), which a realm keeps only for such roots.
	// It is set too on the root of a script or module holding a direct
	// eval call: the code a realm compiles from a string shares the record
	// of the code that evaluates it.
	ScriptOrModule 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

	// Module is the module record of a KindModule template (nil for any
	// other kind).
	Module *Module

	// Extra holds the rarely needed data of scripts, eval code and
	// functions containing a direct eval (nil for everything else, so
	// ordinary functions pay one pointer word).
	Extra *Extra
}

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, each once
	Var      []string // var names that are not also function names
	// AnnexB lists the names only block-level function declarations of
	// sloppy code declare at top level (Annex B.3.2.2): each becomes a var
	// unless a global lexical binding or a non-extensible global object
	// prevents it.
	AnnexB []string
	// Eval marks the declarations of sloppy eval code, whose global
	// bindings are created configurable (EvalDeclarationInstantiation) and
	// which never declares global lexical bindings.
	Eval bool
}

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 Import

type Import struct {
	Request   int    // index into Links.Requests
	Name      string // the imported name (unset for a namespace import)
	Namespace bool
	Slot      int
	Line, Col int32
}

Import is an import binding.

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 script top-level body (Realm.RunScript): its
	// top-level declarations are global bindings reached by name.
	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 Links struct {
	// Requests are the specifiers, each once ([[RequestedModules]]).
	Requests []Request
	// Imports are the import bindings: each Env slot holds a reference to
	// the exporting binding (GetImport), or the namespace object when
	// Namespace is set (`import * as ns`, read with GetEnv).
	Imports []Import
	// Reexports are the indirect exports: `export {x as y} from`, `export *
	// as y from` (All), and `export {x as y}` of an import binding x.
	Reexports []Reexport
	// Stars are the requests of the `export * from` entries.
	Stars []Star
}

Links are the module requests of a module and the entries that name them, each in source order. Line and Col (1-based, the column in code points) locate the specifier or the entry for the errors of linking.

type Module

type Module struct {
	// Exports are the local exports sorted by name.
	Exports []Export
	// BodyPC is the pc of the body after the prologue that writes the TDZ
	// markers and creates the hoisted functions: linking a graph runs the
	// prologue of every module before any body runs (InitializeEnvironment).
	BodyPC int
	// Links is nil when the module requests no other module and uses
	// neither import() nor import.meta, which then evaluates without a
	// module graph (a direct eval in its code alone sets ScriptOrModule
	// and leaves Links nil); Requests is empty when it only uses those.
	Links *Links
}

Module is what a module template records for the host and for linking (ECMA-262 §16.2.1.7 Source Text Module Records). The module Env is the top-level function's own Env, so every local binding, and every exported one, is a CaptureLayout slot.

func (*Module) Export

func (m *Module) Export(name string) (int, bool)

Export returns the Env slot of the local export name, or false.

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

	// --- references (on the jump table, numbered after the ops above so
	// that code without them keeps its encoding) ---
	GetElemRef // ABC+X R[C] = R[X], converted once; R[A] = R[B][R[C]]; X = register

	// --- 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)

	// --- modules ---
	GetImport  // ABC+X  R[A] = the binding env^B[C] refers to; ReferenceError if hole; X = name const
	GetImportW // AB+X+X R[A] = the binding env^B[X1] refers to; ReferenceError if hole; X2 = name const
	ImportCall // AB    R[A] = import(R[B]): a promise for the namespace of the module the host loads for it
	ImportMeta // A     R[A] = import.meta of the running script or module's root

	// --- sloppy mode, script globals and with (dispatched after the async ops) ---
	SetGlobalSloppy // A+X   global[name] = R[A] in sloppy mode: creates an unresolvable name, a rejected write is ignored; X = name:16 | ic:16
	ResolveGlobal   // A+X   R[A] = whether the global environment has a binding name (strict, before the value of an assignment); X = name:16 | ic:16
	SetGlobalRef    // AB+X  global binding name = R[A] (strict) when R[B], ResolveGlobal's result, else ReferenceError; X = name:16 | ic:16 (ResolveGlobal's)
	InitGlobal      // A+X   initialize the script's global lexical binding name to R[A]; X = name:16 | const<<16
	SetGlobalVar    // A+X   Annex B.3.2.2: global[name] = R[A] (sloppy) unless a global lexical binding name exists; X = name const
	DelGlobal       // A+X   R[A] = delete of the global binding name (false for a global lexical); X = name const
	SetPropSloppy   // AB+X  R[A].name = R[B], a rejected assignment ignored; X = name:16 | ic:16
	SetElemSloppy   // ABC   R[A][R[B]] = R[C], a rejected assignment ignored
	DelPropSloppy   // AB+X  R[A] = delete R[B].name, false when rejected; X = name const
	DelElemSloppy   // ABC   R[A] = delete R[B][R[C]], false when rejected
	SetSuperSloppy  // ABC   R[A][R[B]] = R[C] with receiver R[A+1], a rejected assignment ignored
	ToObject        // AB    R[A] = ToObject(R[B]) (the with statement's object)
	JmpWith         // AsBx+X pc += sBx if the with object R[A] has a binding name (HasProperty, not @@unscopables-blocked); X = name const
	WithGet         // AB+X  R[A] = binding name of the with object R[B]; X = name:16 | strict<<16
	WithSet         // AB+X  set binding name of the with object R[A] to R[B]; X = name:16 | strict<<16
	CoerceThis      // -     this = the global object if undefined or null, else ToObject(this) (sloppy function entry)
	MapArguments    // A     make the arguments object R[A] mapped to the parameters in the function's own Env
	CallEval        // ABC+X R[A] = call of callee R[A] with this R[A+1] and args R[A+2..] (B = argc, C = 1: one spread array), a direct eval when the callee is %eval%; X = index into Extra.Evals

)

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 Reexport

type Reexport struct {
	Name      string // the exported name
	Request   int
	Import    string // the imported name (unset when All)
	All       bool
	Line, Col int32
}

Reexport is an indirect export.

type Request

type Request struct {
	Specifier string
	Line, Col int32
}

Request is a module specifier.

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].

type Star

type Star struct {
	Request   int
	Line, Col int32
}

Star is an `export * from` entry.

Jump to

Keyboard shortcuts

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