Documentation
¶
Overview ¶
Package api defines the Lua state, global state, and call frame types.
LuaState is the per-thread (coroutine) state. GlobalState is shared across all threads in a Lua instance. CallInfo represents a single activation record in the call chain.
Reference: .analysis/04-call-return-error.md §1, .analysis/07-runtime-infrastructure.md §2
LuaState object pool — reuses dead thread structs to reduce allocation pressure.
Coroutines are the most expensive objects to create in go-lua because each LuaState includes a large stack slice (~200 StackValues). Using sync.Pool lets us reuse both the struct and the stack slice for short-lived coroutines.
LuaState initialization and stack management.
Reference: lua-master/lstate.c
Index ¶
- Constants
- func CloseState(L *LuaState)
- func DefaultWarnHandler(g *GlobalState)
- func EnsureStack(L *LuaState, n int)
- func FreeCI(L *LuaState)
- func GrowStack(L *LuaState, n int)
- func PushValue(L *LuaState, v object.TValue)
- func PutLuaState(L *LuaState)
- func ShrinkCI(L *LuaState)
- func StackCheck(L *LuaState, n int) bool
- type CFunction
- type CallInfo
- type GlobalState
- type KFunction
- type LuaBaseLevel
- type LuaError
- type LuaState
- type LuaYield
Constants ¶
const ( StatusOK = 0 // LUA_OK StatusYield = 1 // LUA_YIELD StatusErrRun = 2 // LUA_ERRRUN StatusErrSyntax = 3 // LUA_ERRSYNTAX StatusErrMem = 4 // LUA_ERRMEM StatusErrErr = 5 // LUA_ERRERR // StatusCloseKTop: special status for closing TBC variables without // resetting L.Top. Used by OP_RETURN k-bit path where return values // sit on the stack above the TBC variables. // Matches C Lua's CLOSEKTOP = LUA_ERRERR + 1 in lfunc.h. StatusCloseKTop = 6 )
--------------------------------------------------------------------------- Thread status codes (matches C TStatus) ---------------------------------------------------------------------------
const ( CISTNResults uint32 = 0xFF // bits 0-7: nresults + 1 CISTC uint32 = 1 << 15 // call is running a C function CISTFresh uint32 = 1 << 16 // fresh luaV_execute frame CISTClsRet uint32 = 1 << 17 // closing tbc variables on return CISTTBC uint32 = 1 << 18 // has to-be-closed variables CISTOAH uint32 = 1 << 19 // original allowhook value CISTHooked uint32 = 1 << 20 // running a debug hook CISTYPCall uint32 = 1 << 21 // yieldable protected call CISTTail uint32 = 1 << 22 // call was tail called CISTHookYield uint32 = 1 << 23 // last hook call yielded CISTFin uint32 = 1 << 24 // function called a finalizer CISTCCMTShift = 8 // bits 8-11: __call metamethod count CISTCCMTMask = 0xF << CISTCCMTShift CISTRecstShift = 12 // bits 12-14: recovery status )
--------------------------------------------------------------------------- CallInfo status flags (packed into CallStatus uint32) Matches C exactly — verified against lstate.h ---------------------------------------------------------------------------
const ( HookCall = 0 HookReturn = 1 HookLine = 2 HookCount = 3 HookTailCall = 4 )
Hook event constants (matches C LUA_HOOK*)
const ( MaskCall = 1 << 0 // LUA_MASKCALL MaskRet = 1 << 1 // LUA_MASKRET MaskLine = 1 << 2 // LUA_MASKLINE MaskCount = 1 << 3 // LUA_MASKCOUNT )
--------------------------------------------------------------------------- Hook mask constants (matches C LUA_MASK*) ---------------------------------------------------------------------------
const ( RegistryIndexGlobals = 2 // LUA_RIDX_GLOBALS RegistryIndexMainThread = 3 // LUA_RIDX_MAINTHREAD RegistryIndexLast = 3 // LUA_RIDX_LAST )
--------------------------------------------------------------------------- Registry indices (matches C LUA_RIDX_*) ---------------------------------------------------------------------------
const BasicStackSize = 200
BasicStackSize is the initial stack allocation. Go pays higher cost for stack growth (alloc+copy+GC) than C, so we start larger to avoid reallocStack calls in typical programs like Fibonacci(20).
const ExtraStack = 5
ExtraStack is reserved space beyond stack_last for error handling.
const MaxCCalls = 200
MaxCCalls is the maximum C call depth before stack overflow.
const MaxResults = 250
MaxResults is the maximum number of results a function can return.
const MaxStack = 1_000_000
MaxStack is the maximum Lua stack size.
const MultiRet = -1
MultiRet signals "all results" in call/return (LUA_MULTRET = -1).
Variables ¶
This section is empty.
Functions ¶
func CloseState ¶
func CloseState(L *LuaState)
CloseState cleans up a Lua state. In Go, most cleanup is handled by GC, but we nil out references to help the collector. Mirrors C Lua's close_state: runs all pending __gc finalizers before closing.
func DefaultWarnHandler ¶
func DefaultWarnHandler(g *GlobalState)
DefaultWarnHandler is the standard warning handler installed by luaL_newstate. It supports @on/@off control messages and prints warnings to stderr. The handler uses a state machine with three modes:
- warnOff: warnings are off (only @on control message is processed)
- warnOn: ready for a new message (checks control messages, prints prefix)
- warnCont: continuing a multi-part message
State is stored via closure over a *warnState.
func EnsureStack ¶
EnsureStack ensures at least n free stack slots, growing if needed. This is the primary function other modules should call.
func FreeCI ¶
func FreeCI(L *LuaState)
FreeCI frees all CallInfo nodes after the current one. Mirrors: freeCI in lstate.c
func GrowStack ¶
GrowStack ensures there are at least n free stack slots above L.Top. If not enough space, reallocates the stack. Mirrors: luaD_growstack / luaD_reallocstack in ldo.c
func PushValue ¶
PushValue pushes a TValue onto the stack and increments Top. Panics if stack overflow.
func PutLuaState ¶
func PutLuaState(L *LuaState)
PutLuaState returns a LuaState to the pool for reuse. Called by the GC sweep phase when a dead thread is unlinked. Clears all reference fields before pooling to help Go's GC, but retains the Stack and CISlab slice capacities for reuse.
func ShrinkCI ¶
func ShrinkCI(L *LuaState)
ShrinkCI frees half of the unused CallInfo nodes. Mirrors: luaE_shrinkCI in lstate.c
func StackCheck ¶
StackCheck checks that there are at least n free stack slots. Returns true if enough space exists, false otherwise.
Types ¶
type CFunction ¶
--------------------------------------------------------------------------- CFunction is the CANONICAL type for Go functions callable from Lua. It receives the Lua state and returns the number of results pushed. All other modules should reference this type (or alias it). ---------------------------------------------------------------------------
type CallInfo ¶
type CallInfo struct {
Func int // stack index of function slot
Top int // stack index of top for this call
Prev *CallInfo // caller's CallInfo
Next *CallInfo // callee's CallInfo (allocated lazily)
// Lua function fields (valid when CallStatus & CISTC == 0)
SavedPC int // index into Proto.Code (next instruction)
Trap bool // tracing active (hooks)
NExtraArgs int // extra vararg arguments
// C function fields (valid when CallStatus & CISTC != 0)
K KFunction // continuation for yields
OldErrFunc int // saved error function stack index
Ctx int // continuation context
// Ephemeral union (reused for different purposes)
NYield int // number of values yielded
NRes int // number of values returned
FuncIdx int // saved function index for pcall recovery (mirrors ci->u2.funcidx)
CallStatus uint32 // CIST_* flags
}
--------------------------------------------------------------------------- CallInfo is the activation record for a single function call. Forms a doubly-linked list. The Lua/C distinction is handled by checking CallStatus & CISTC. ---------------------------------------------------------------------------
func NewCI ¶
NewCI allocates or reuses the next CallInfo in the chain. Mirrors: luaE_extendCI in lstate.c
func (*CallInfo) GetRecst ¶
GetRecst retrieves the recovery status from bits 12-14 of CallStatus. Mirrors: getcistrecst in C Lua (lstate.h)
func (*CallInfo) NResults ¶
NResults returns the number of results the caller expects. Returns MultiRet (-1) if caller wants all results.
func (*CallInfo) SetNResults ¶
SetNResults encodes the expected result count into CallStatus.
type GlobalState ¶
type GlobalState struct {
Registry object.TValue // the registry table
Seed uint32 // randomized hash seed
// I1 FIX: Concrete types where no circular dependency exists
TMNames [25]*object.LuaString // metamethod name strings
MT [9]any // metatables for basic types (9 = NumTypes, any to avoid Table import cycle)
MainThread *LuaState // the main thread
Panic CFunction // unprotected error handler
MemErrMsg *object.LuaString // pre-allocated "not enough memory" string
// String interning table (typed in luastring module)
StringTable any
// API string cache (typed in luastring module)
StringCache any
// MemoryLimit is the maximum number of bytes Lua objects may use.
// 0 means no limit. When GCTotalBytes exceeds this after a full GC,
// further allocations panic with StatusErrMem ("not enough memory").
MemoryLimit int64
// GCTotalBytes tracks total Lua-level object allocations (bytes).
// Mirrors C Lua's gettotalbytes(g) for collectgarbage("count").
// Incremented on allocation, decremented by V5 GC sweep when dead
// objects are removed from allgc. Single-threaded access only.
GCTotalBytes int64
// GCAllocCount counts table allocations since the last GC cycle.
// Used to trigger periodic GC during tight allocation loops.
GCAllocCount int64
// GCCountdown is a countdown counter for periodic GC triggering.
// Starts at 5000, decrements each checkGC call. When ≤ 0, triggers GC
// and resets. Uses countdown instead of modulo for lower inline cost.
GCCountdown int64
// GCStepFn is set by the API layer to run a full GC cycle.
// The VM calls this periodically during allocation-heavy loops.
// Signature: func(L *LuaState) — runs GCCollect.
GCStepFn func(L *LuaState)
// GCDrainFn is set by the API layer to run a lightweight GC cycle.
// Signature: func(L *LuaState) — runs GCCollect.
GCDrainFn func(L *LuaState)
// SweepStringFn is called by GC sweep when a dead short string is found.
// It removes the string from the string interning table.
// Set by the API layer to avoid circular imports (gc → luastring).
SweepStringFn func(obj object.GCObject)
// GCClosed is set true when the state is closing — suppresses further GC.
GCClosed bool
// GCStopped is set true by collectgarbage("stop") — suppresses periodic GC.
GCStopped bool
// GCRunning is true while a GC cycle is executing — prevents re-entrant GC.
// Mirrors C Lua's g->gcrunning flag.
GCRunning bool
// GCRunningFinalizer is true while __gc finalizers are being called.
// Prevents reentrant finalization (mirrors C Lua's GCSTPGC flag in gcstp).
GCRunningFinalizer bool
// GCExplicit is true when GC is triggered by explicit collectgarbage() call.
// When true, traverseThread uses th.Top (precise — dead registers not marked).
// When false (periodic GC), traverseThread uses maxTop (conservative).
GCExplicit bool
// GCMode tracks the current GC mode: "incremental" (default) or "generational".
// Mirrors C Lua's g->gckind (KGC_INC / KGC_GEN).
GCMode string
// GCParams stores GC tuning parameters (pause, stepmul, stepsize, etc.).
// Go's GC doesn't use these, but we store them so Lua code that
// reads/writes them (e.g., gc.lua tests) works correctly.
// Keys: "pause", "stepmul", "stepsize", "minormul", "majorminor", "minormajor"
GCParams map[string]int64
// Object chains
Allgc object.GCObject // head of all collectable objects
FinObj object.GCObject // objects with __gc (separated at setmetatable time)
TobeFnz object.GCObject // objects whose __gc should run this cycle
FixedGC object.GCObject // permanent objects (never collected)
// GC phase
GCState byte // current phase (GCSpause, GCSpropagate, etc.)
CurrentWhite byte // current white bit (flips each cycle)
// Gray lists (slice-based for cache locality; replaces intrusive GCList)
Gray []object.GCObject // objects to be traversed (stack: pop from end)
GrayAgain []object.GCObject // barrier-back objects (re-traverse in atomic)
Weak []object.GCObject // weak-value tables to clear after mark
AllWeak []object.GCObject // all-weak (kv) tables
Ephemeron []object.GCObject // ephemeron tables (weak-key)
// EphemeronCount tracks how many weak-key (ephemeron) tables were
// encountered during the current GC mark phase. When zero, the
// expensive clearDeadKeysAllEphemerons walk can be skipped entirely.
EphemeronCount int
// Incremental GC state
GCDebt int64 // bytes "owed" — positive = credit, triggers step when <= 0
GCEstimate int64 // estimate of non-garbage bytes (for setpause)
SweepGC *object.GCObject // current position in sweep list (nil = not sweeping)
// GC tuning parameters (used by debt-based pacing)
GCPause int // pause% (default 200 = collect when memory reaches 2x live)
GCStepMul int // step multiplier (default 200)
GCStepSize int // log2 of step size in bytes (default 13 = 8KB)
// Generational GC state
GCKind byte // KGC_INC=0, KGC_GENMINOR=1, KGC_GENMAJOR=2
// Generation list boundary pointers within allgc chain.
// The allgc chain is ordered: [new objects] → Survival → Old1 → ReallyOld → nil
// These pointers mark the boundaries between generations.
Survival object.GCObject // first survival-age object in allgc
Old1 object.GCObject // first old1-age object in allgc
ReallyOld object.GCObject // first really-old object in allgc
FirstOld1 object.GCObject // optimization: first OLD1 in list
// Same boundaries for finobj chain
FinObjSur object.GCObject // survival boundary in finobj
FinObjOld1 object.GCObject // old1 boundary in finobj
FinObjROld object.GCObject // really-old boundary in finobj
// GCMinorMul is the generational minor collection multiplier.
// Controls when minor GC switches to major (% of live memory growth).
GCMinorMul int // default 25 (LUAI_GENMINORMUL)
// WarnF is the warning handler function. Called with (message, tocont).
// tocont=true means the message is a continuation (more parts follow).
// When nil, warnings are silently discarded.
WarnF func(ud any, message string, tocont bool)
// WarnUd is the user data passed to WarnF (mirrors C Lua's ud_warn).
WarnUd any
// WarnBuf accumulates multi-part warning messages (tocont=true parts).
WarnBuf string
}
--------------------------------------------------------------------------- GlobalState is shared across all threads in a Lua instance. ---------------------------------------------------------------------------
func (*GlobalState) LinkGC ¶
func (g *GlobalState) LinkGC(obj object.GCObject)
--------------------------------------------------------------------------- LinkGC links a new collectable object into the allgc chain and sets its initial white mark. This is the Go equivalent of C Lua's luaC_newobj. Must be called for every new collectable object immediately after creation. ---------------------------------------------------------------------------
func (*GlobalState) SetWarnF ¶
func (g *GlobalState) SetWarnF(f func(ud any, msg string, tocont bool), ud any)
SetWarnF sets the warning handler function and its user data. Mirrors C Lua's lua_setwarnf.
func (*GlobalState) TrackAllocation ¶
func (g *GlobalState) TrackAllocation(n int64)
TrackAllocation increments GCTotalBytes and decrements GCDebt by n bytes. Used for debt-based GC pacing: when GCDebt reaches 0, a GC step triggers. Lua is single-threaded so no atomics needed.
If a MemoryLimit is set and GCTotalBytes exceeds it, a full GC is attempted (via GCDrainFn). If still over limit after GC, panics with StatusErrMem.
func (*GlobalState) WarnError ¶
func (g *GlobalState) WarnError(where string, errMsg string)
WarnError generates a warning from a __gc error. Produces: "error in __gc (errmsg)" Mirrors C Lua's luaE_warnerror (lstate.c).
func (*GlobalState) Warning ¶
func (g *GlobalState) Warning(msg string, tocont bool)
Warning issues a warning message through the registered handler. If tocont is true, the message is a continuation (more parts follow). Mirrors C Lua's luaE_warning (lstate.c).
type LuaBaseLevel ¶
type LuaBaseLevel struct {
Status int // status from resetthread (usually StatusOK)
}
--------------------------------------------------------------------------- LuaBaseLevel is thrown by CloseThread when a coroutine closes itself. Mirrors C Lua's luaD_throwbaselevel: bypasses all inner error handlers (pcall) and propagates directly to the outermost RunProtected (Resume). RunProtected catches this and re-panics; Resume catches it as termination. ---------------------------------------------------------------------------
type LuaError ¶
type LuaError struct {
Status int // error code (StatusErrRun, etc.)
Message object.TValue // error object (usually a string)
}
--------------------------------------------------------------------------- LuaError is the CANONICAL error type used for Lua runtime errors. Lua errors are propagated via panic(LuaError{...}). All modules should use this type (not define their own). ---------------------------------------------------------------------------
type LuaState ¶
type LuaState struct {
object.GCHeader // GC metadata
// C3 FIX: Stack uses []StackValue (not []TValue) for TBC support.
// Each slot has a TBCDelta field for the to-be-closed linked list.
Stack []object.StackValue // the value stack
Top int // index of first free slot
CI *CallInfo // current call info
BaseCI CallInfo // embedded base CallInfo (C host level)
Global *GlobalState // shared global state
OpenUpval any // head of open upvalue list (typed in closure module)
TBCList int // stack index of top to-be-closed variable (-1 = none)
Status int // thread status (StatusOK, StatusYield, etc.)
AllowHook bool // hook enable flag
NCCalls uint32 // C call depth (low 16) + non-yieldable count (high 16)
NCI int // number of CallInfo nodes in the list
ErrFunc int // error handler stack index
OldPC int // last traced PC
// CallInfo slab allocation — reduces GC pressure by allocating
// CallInfos in batches of ciSlabSize instead of individually.
CISlab []CallInfo // slab for CallInfo allocation
CISlabIdx int // next free index in slab
// C10 FIX: Debug hook fields (needed by debug.sethook/gethook)
Hook any // debug hook function (typed later)
BaseHookCount int // base hook count setting
HookCount int // current hook countdown
HookMask int // which hooks active (call, return, line, count)
FTransfer int // hook value transfer: index of first value
NTransfer int // hook value transfer: number of values
HookEvent int // current hook event (HookCall, HookReturn, etc.)
HookLine int // current hook line number (-1 if not a line hook)
// Saved state for hook yield resume (survives panic/yield)
HookSavedTop int // L.Top before hook dispatch
HookSavedCITop int // ci.Top before hook dispatch
// APIState caches the public api.State wrapper for this LuaState.
// This avoids allocating a new &State{Internal: ls} on every C function call.
// Set once during state creation; type is any to avoid circular import.
APIState any
}
--------------------------------------------------------------------------- LuaState is the per-thread (coroutine) state. Each coroutine has its own LuaState with its own stack. ---------------------------------------------------------------------------
func NewState ¶
func NewState() *LuaState
NewState creates a new Lua state with stack, base CI, registry, globals, string table, and TM names. This is the Go equivalent of lua_newstate.
type LuaYield ¶
type LuaYield struct {
NResults int // number of results to yield
}
--------------------------------------------------------------------------- LuaYield is the type used for coroutine yield via panic/recover. Distinct from LuaError so recover() can distinguish error from yield. I5 FIX: Added for coroutine support. ---------------------------------------------------------------------------