profiler/lua_state.h (648 lines of code) (raw):
/*
** LuaJIT common internal definitions for profiler to get BTF format.
** Copyright (C) 2005-2022 Mike Pall. See Copyright Notice in luajit.h
**
** 17-Jul-2022 Yusheng Zheng modified this from lua.h, lua_state.h and
** lj_def.h.
*/
#ifndef __LUA_STATE_H
#define __LUA_STATE_H
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
#define LJ_TARGET_GC64 1
/* 64 bit GC references. */
#if LJ_TARGET_GC64
#define LJ_GC64 1
#else
#define LJ_GC64 0
#endif
/* GCobj reference */
typedef struct GCRef
{
#if LJ_GC64
uint64_t gcptr64; /* True 64 bit pointer. */
#else
uint32_t gcptr32; /* Pseudo 32 bit pointer. */
#endif
} GCRef;
/* 2-slot frame info. */
#if LJ_GC64
#define LJ_FR2 1
#else
#define LJ_FR2 0
#endif
/* Optional defines. */
#ifndef LJ_FASTCALL
#define LJ_FASTCALL
#endif
#ifndef LJ_NORET
#define LJ_NORET
#endif
#ifndef LJ_NOAPI
#define LJ_NOAPI extern
#endif
#ifndef LJ_LIKELY
#define LJ_LIKELY(x) (x)
#define LJ_UNLIKELY(x) (x)
#endif
/* Attributes for internal functions. */
#define LJ_DATA LJ_NOAPI
#define LJ_DATADEF
#define LJ_ASMF LJ_NOAPI
#define LJ_FUNCA LJ_NOAPI
#if defined(ljamalg_c)
#define LJ_FUNC static
#else
#define LJ_FUNC LJ_NOAPI
#endif
#define LJ_FUNC_NORET LJ_FUNC LJ_NORET
#define LJ_FUNCA_NORET LJ_FUNCA LJ_NORET
#define LJ_ASMF_NORET LJ_ASMF LJ_NORET
/* Internal assertions. */
#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK)
#define lj_assert_check(g, c, ...) \
((c) ? (void)0 : (lj_assert_fail((g), __FILE__, __LINE__, __func__, __VA_ARGS__), 0))
#define lj_checkapi(c, ...) lj_assert_check(G(L), (c), __VA_ARGS__)
#else
#define lj_checkapi(c, ...) ((void)L)
#endif
#ifdef LUA_USE_ASSERT
#define lj_assertG_(g, c, ...) lj_assert_check((g), (c), __VA_ARGS__)
#define lj_assertG(c, ...) lj_assert_check(g, (c), __VA_ARGS__)
#define lj_assertL(c, ...) lj_assert_check(G(L), (c), __VA_ARGS__)
#define lj_assertX(c, ...) lj_assert_check(NULL, (c), __VA_ARGS__)
#define check_exp(c, e) (lj_assertX((c), #c), (e))
#else
#define lj_assertG_(g, c, ...) ((void)0)
#define lj_assertG(c, ...) ((void)g)
#define lj_assertL(c, ...) ((void)L)
#define lj_assertX(c, ...) ((void)0)
#define check_exp(c, e) (e)
#endif
/* Static assertions. */
#define LJ_ASSERT_NAME2(name, line) name##line
#define LJ_ASSERT_NAME(line) LJ_ASSERT_NAME2(lj_assert_, line)
#ifdef __COUNTER__
#define LJ_STATIC_ASSERT(cond) \
extern void LJ_ASSERT_NAME(__COUNTER__)(int STATIC_ASSERTION_FAILED[(cond) ? 1 : -1])
#else
#define LJ_STATIC_ASSERT(cond) \
extern void LJ_ASSERT_NAME(__LINE__)(int STATIC_ASSERTION_FAILED[(cond) ? 1 : -1])
#endif
/* PRNG state. Need this here, details in lj_prng.h. */
typedef struct PRNGState
{
uint64_t u[4];
} PRNGState;
/* Common GC header for all collectable objects. */
#define GCHeader \
GCRef nextgc; \
uint8_t marked; \
uint8_t gct
/* This occupies 6 bytes, so use the next 2 bytes for non-32 bit fields. */
/* Memory reference */
typedef struct MRef
{
#if LJ_GC64
uint64_t ptr64; /* True 64 bit pointer. */
#else
uint32_t ptr32; /* Pseudo 32 bit pointer. */
#endif
} MRef;
#if LJ_GC64
#define mref(r, t) ((t *)(void *)(r).ptr64)
#define mrefu(r) ((r).ptr64)
#define setmref(r, p) ((r).ptr64 = (uint64_t)(void *)(p))
#define setmrefu(r, u) ((r).ptr64 = (uint64_t)(u))
#define setmrefr(r, v) ((r).ptr64 = (v).ptr64)
#else
#define mref(r, t) ((t *)(void *)(uintptr_t)(r).ptr32)
#define mrefu(r) ((r).ptr32)
#define setmref(r, p) ((r).ptr32 = (uint32_t)(uintptr_t)(void *)(p))
#define setmrefu(r, u) ((r).ptr32 = (uint32_t)(u))
#define setmrefr(r, v) ((r).ptr32 = (v).ptr32)
#endif
#define LJ_ALIGN(n) __attribute__((aligned(n)))
#define LUA_NUMBER double
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;
#if LJ_ARCH_ENDIAN == LUAJIT_BE
#define LJ_LE 0
#define LJ_BE 1
#define LJ_ENDIAN_SELECT(le, be) be
#define LJ_ENDIAN_LOHI(lo, hi) hi lo
#else
#define LJ_LE 1
#define LJ_BE 0
#define LJ_ENDIAN_SELECT(le, be) le
#define LJ_ENDIAN_LOHI(lo, hi) lo hi
#endif
/* Frame link. */
typedef union
{
int32_t ftsz; /* Frame type and size of previous frame. */
MRef pcr; /* Or PC for Lua frames. */
} FrameLink;
/* Tagged value. */
typedef LJ_ALIGN(8) union TValue
{
uint64_t u64; /* 64 bit pattern overlaps number. */
lua_Number n; /* Number object overlaps split tag/value object. */
#if LJ_GC64
GCRef gcr; /* GCobj reference with tag. */
int64_t it64;
struct
{
LJ_ENDIAN_LOHI(
int32_t i; /* Integer value. */
, uint32_t it; /* Internal object tag. Must overlap MSW of number. */
)
};
#else
struct
{
LJ_ENDIAN_LOHI(
union {
GCRef gcr; /* GCobj reference (if any). */
int32_t i; /* Integer value. */
};
, uint32_t it; /* Internal object tag. Must overlap MSW of number. */
)
};
#endif
#if LJ_FR2
int64_t ftsz; /* Frame type and size of previous frame, or PC. */
#else
struct
{
LJ_ENDIAN_LOHI(
GCRef func; /* Function for next frame (or dummy L). */
, FrameLink tp; /* Link to previous frame. */
)
} fr;
#endif
struct
{
LJ_ENDIAN_LOHI(
uint32_t lo; /* Lower 32 bits of number. */
, uint32_t hi; /* Upper 32 bits of number. */
)
} u32;
} TValue;
/* Memory and GC object sizes. */
typedef uint32_t MSize;
#if LJ_GC64
typedef uint64_t GCSize;
#else
typedef uint32_t GCSize;
#endif
/* Per-thread state object. */
struct lua_State
{
GCHeader;
uint8_t dummy_ffid; /* Fake FF_C for curr_funcisL() on dummy frames. */
uint8_t status; /* Thread status. */
MRef glref; /* Link to global state. */
GCRef gclist; /* GC chain. */
TValue *base; /* Base of currently executing function. */
TValue *top; /* First free slot in the stack. */
MRef maxstack; /* Last free slot in the stack. */
MRef stack; /* Stack base. */
GCRef openupval; /* List of open upvalues in the stack. */
GCRef env; /* Thread environment (table of globals). */
void *cframe; /* End of C stack frame chain. */
MSize stacksize; /* True stack size (incl. LJ_STACK_EXTRA). */
void *exdata; /* user extra data pointer. added by OpenResty */
void *exdata2; /* the 2nd user extra data pointer. added by OpenResty */
#if LJ_TARGET_ARM
uint32_t unused1;
uint32_t unused2;
#endif
};
typedef struct lua_State lua_State;
typedef int (*lua_CFunction)(lua_State *L);
typedef const TValue cTValue;
/* Internal object tags.
**
** Format for 32 bit GC references (!LJ_GC64):
**
** Internal tags overlap the MSW of a number object (must be a double).
** Interpreted as a double these are special NaNs. The FPU only generates
** one type of NaN (0xfff8_0000_0000_0000). So MSWs > 0xfff80000 are available
** for use as internal tags. Small negative numbers are used to shorten the
** encoding of type comparisons (reg/mem against sign-ext. 8 bit immediate).
**
** ---MSW---.---LSW---
** primitive types | itype | |
** lightuserdata | itype | void * | (32 bit platforms)
** lightuserdata |ffff|seg| ofs | (64 bit platforms)
** GC objects | itype | GCRef |
** int (LJ_DUALNUM)| itype | int |
** number -------double------
**
** Format for 64 bit GC references (LJ_GC64):
**
** The upper 13 bits must be 1 (0xfff8...) for a special NaN. The next
** 4 bits hold the internal tag. The lowest 47 bits either hold a pointer,
** a zero-extended 32 bit integer or all bits set to 1 for primitive types.
**
** ------MSW------.------LSW------
** primitive types |1..1|itype|1..................1|
** GC objects |1..1|itype|-------GCRef--------|
** lightuserdata |1..1|itype|seg|------ofs-------|
** int (LJ_DUALNUM) |1..1|itype|0..0|-----int-------|
** number ------------double-------------
**
** ORDER LJ_T
** Primitive types nil/false/true must be first, lightuserdata next.
** GC objects are at the end, table/userdata must be lowest.
** Also check lj_ir.h for similar ordering constraints.
*/
#define LJ_TNIL (~0u)
#define LJ_TFALSE (~1u)
#define LJ_TTRUE (~2u)
#define LJ_TLIGHTUD (~3u)
#define LJ_TSTR (~4u)
#define LJ_TUPVAL (~5u)
#define LJ_TTHREAD (~6u)
#define LJ_TPROTO (~7u)
#define LJ_TFUNC (~8u)
#define LJ_TTRACE (~9u)
#define LJ_TCDATA (~10u)
#define LJ_TTAB (~11u)
#define LJ_TUDATA (~12u)
/* This is just the canonical number type used in some places. */
#define LJ_TNUMX (~13u)
/* Integers have itype == LJ_TISNUM doubles have itype < LJ_TISNUM */
#if LJ_64 && !LJ_GC64
#define LJ_TISNUM 0xfffeffffu
#else
#define LJ_TISNUM LJ_TNUMX
#endif
#define LJ_TISTRUECOND LJ_TFALSE
#define LJ_TISPRI LJ_TTRUE
#define LJ_TISGCV (LJ_TSTR + 1)
#define LJ_TISTABUD LJ_TTAB
/* Type marker for slot holding a traversal index. Must be lightuserdata. */
#define LJ_KEYINDEX 0xfffe7fffu
#if LJ_GC64
#define LJ_GCVMASK (((uint64_t)1 << 47) - 1)
#endif
#if LJ_64
/* To stay within 47 bits, lightuserdata is segmented. */
#define LJ_LIGHTUD_BITS_SEG 8
#define LJ_LIGHTUD_BITS_LO (47 - LJ_LIGHTUD_BITS_SEG)
#endif
/* -- Common type definitions --------------------------------------------- */
/* Types for handling bytecodes. Need this here, details in lj_bc.h. */
typedef uint32_t BCIns; /* Bytecode instruction. */
typedef uint32_t BCPos; /* Bytecode position. */
typedef uint32_t BCReg; /* Bytecode register. */
typedef int32_t BCLine; /* Bytecode line number. */
/* Internal assembler functions. Never call these directly from C. */
typedef void (*ASMFunction)(void);
/* Resizable string buffer. Need this here, details in lj_buf.h. */
#define SBufHeader \
char *w, *e, *b; \
MRef L
typedef struct SBuf
{
SBufHeader;
} SBuf;
/* Operand ranges and related constants. */
#define BCMAX_A 0xff
#define BCMAX_B 0xff
#define BCMAX_C 0xff
#define BCMAX_D 0xffff
#define BCBIAS_J 0x8000
#define NO_REG BCMAX_A
#define NO_JMP (~(BCPos)0)
/* Macros to get instruction fields. */
#define bc_op(i) ((BCOp)((i)&0xff))
#define bc_a(i) ((BCReg)(((i) >> 8) & 0xff))
#define bc_b(i) ((BCReg)((i) >> 24))
#define bc_c(i) ((BCReg)(((i) >> 16) & 0xff))
#define bc_d(i) ((BCReg)((i) >> 16))
#define bc_j(i) ((ptrdiff_t)bc_d(i) - BCBIAS_J)
/* Macros to set instruction fields. */
#define setbc_byte(p, x, ofs) \
((uint8_t *)(p))[LJ_ENDIAN_SELECT(ofs, 3 - ofs)] = (uint8_t)(x)
#define setbc_op(p, x) setbc_byte(p, (x), 0)
#define setbc_a(p, x) setbc_byte(p, (x), 1)
#define setbc_b(p, x) setbc_byte(p, (x), 3)
#define setbc_c(p, x) setbc_byte(p, (x), 2)
#define setbc_d(p, x) \
((uint16_t *)(p))[LJ_ENDIAN_SELECT(1, 0)] = (uint16_t)(x)
#define setbc_j(p, x) setbc_d(p, (BCPos)((int32_t)(x) + BCBIAS_J))
/* Macros to compose instructions. */
#define BCINS_ABC(o, a, b, c) \
(((BCIns)(o)) | ((BCIns)(a) << 8) | ((BCIns)(b) << 24) | ((BCIns)(c) << 16))
#define BCINS_AD(o, a, d) \
(((BCIns)(o)) | ((BCIns)(a) << 8) | ((BCIns)(d) << 16))
#define BCINS_AJ(o, a, j) BCINS_AD(o, a, (BCPos)((int32_t)(j) + BCBIAS_J))
#if LJ_GC64
#define gcref(r) ((GCobj *)(r).gcptr64)
#define gcrefp(r, t) ((t *)(void *)(r).gcptr64)
#define gcrefu(r) ((r).gcptr64)
#define gcrefeq(r1, r2) ((r1).gcptr64 == (r2).gcptr64)
#define setgcref(r, gc) ((r).gcptr64 = (uint64_t) & (gc)->gch)
#define setgcreft(r, gc, it) \
(r).gcptr64 = (uint64_t) & (gc)->gch | (((uint64_t)(it)) << 47)
#define setgcrefp(r, p) ((r).gcptr64 = (uint64_t)(p))
#define setgcrefnull(r) ((r).gcptr64 = 0)
#define setgcrefr(r, v) ((r).gcptr64 = (v).gcptr64)
#else
#define gcref(r) ((GCobj *)(uintptr_t)(r).gcptr32)
#define gcrefp(r, t) ((t *)(void *)(uintptr_t)(r).gcptr32)
#define gcrefu(r) ((r).gcptr32)
#define gcrefeq(r1, r2) ((r1).gcptr32 == (r2).gcptr32)
#define setgcref(r, gc) ((r).gcptr32 = (uint32_t)(uintptr_t) & (gc)->gch)
#define setgcrefp(r, p) ((r).gcptr32 = (uint32_t)(uintptr_t)(p))
#define setgcrefnull(r) ((r).gcptr32 = 0)
#define setgcrefr(r, v) ((r).gcptr32 = (v).gcptr32)
#endif
#define tvref(r) (mref(r, TValue))
/* -- String object ------------------------------------------------------- */
typedef uint32_t StrHash; /* String hash value. */
typedef uint32_t StrID; /* String ID. */
/* String object header. String payload follows. */
typedef struct GCstr
{
GCHeader;
uint8_t reserved; /* Used by lexer for fast lookup of reserved words. */
uint8_t hashalg; /* Hash algorithm. */
StrID sid; /* Interned string ID. */
StrHash hash; /* Hash of string. */
MSize len; /* Size of string. */
} GCstr;
#define strref(r) (&gcref((r))->str)
#define strdata(s) ((const char *)((s) + 1))
#define strdatawr(s) ((char *)((s) + 1))
/* -- Userdata object ----------------------------------------------------- */
/* Userdata object. Payload follows. */
typedef struct GCudata
{
GCHeader;
uint8_t udtype; /* Userdata type. */
uint8_t unused2;
GCRef env; /* Should be at same offset in GCfunc. */
MSize len; /* Size of payload. */
GCRef metatable; /* Must be at same offset in GCtab. */
uint32_t align1; /* To force 8 byte alignment of the payload. */
} GCudata;
/* Userdata types. */
enum
{
UDTYPE_USERDATA, /* Regular userdata. */
UDTYPE_IO_FILE, /* I/O library FILE. */
UDTYPE_FFI_CLIB, /* FFI C library namespace. */
UDTYPE_BUFFER, /* String buffer. */
UDTYPE__MAX
};
#define uddata(u) ((void *)((u) + 1))
#define sizeudata(u) (sizeof(struct GCudata) + (u)->len)
/* -- C data object ------------------------------------------------------- */
/* C data object. Payload follows. */
typedef struct GCcdata
{
GCHeader;
uint16_t ctypeid; /* C type ID. */
} GCcdata;
/* Prepended to variable-sized or realigned C data objects. */
typedef struct GCcdataVar
{
uint16_t offset; /* Offset to allocated memory (relative to GCcdata). */
uint16_t extra; /* Extra space allocated (incl. GCcdata + GCcdatav). */
MSize len; /* Size of payload. */
} GCcdataVar;
#define cdataptr(cd) ((void *)((cd) + 1))
#define cdataisv(cd) ((cd)->marked & 0x80)
#define cdatav(cd) ((GCcdataVar *)((char *)(cd) - sizeof(GCcdataVar)))
#define cdatavlen(cd) check_exp(cdataisv(cd), cdatav(cd)->len)
#define sizecdatav(cd) (cdatavlen(cd) + cdatav(cd)->extra)
#define memcdatav(cd) ((void *)((char *)(cd)-cdatav(cd)->offset))
/* -- Prototype object ---------------------------------------------------- */
#define SCALE_NUM_GCO ((int32_t)sizeof(lua_Number) / sizeof(GCRef))
#define round_nkgc(n) (((n) + SCALE_NUM_GCO - 1) & ~(SCALE_NUM_GCO - 1))
typedef struct GCproto
{
GCHeader;
uint8_t numparams; /* Number of parameters. */
uint8_t framesize; /* Fixed frame size. */
MSize sizebc; /* Number of bytecode instructions. */
#if LJ_GC64
uint32_t unused_gc64;
#endif
GCRef gclist;
MRef k; /* Split constant array (points to the middle). */
MRef uv; /* Upvalue list. local slot|0x8000 or parent uv idx. */
MSize sizekgc; /* Number of collectable constants. */
MSize sizekn; /* Number of lua_Number constants. */
MSize sizept; /* Total size including colocated arrays. */
uint8_t sizeuv; /* Number of upvalues. */
uint8_t flags; /* Miscellaneous flags (see below). */
uint16_t trace; /* Anchor for chain of root traces. */
/* ------ The following fields are for debugging/tracebacks only ------ */
GCRef chunkname; /* Name of the chunk this function was defined in. */
BCLine firstline; /* First line of the function definition. */
BCLine numline; /* Number of lines for the function definition. */
MRef lineinfo; /* Compressed map from bytecode ins. to source line. */
MRef uvinfo; /* Upvalue names. */
MRef varinfo; /* Names and compressed extents of local variables. */
} GCproto;
/* Flags for prototype. */
#define PROTO_CHILD 0x01 /* Has child prototypes. */
#define PROTO_VARARG 0x02 /* Vararg function. */
#define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */
#define PROTO_NOJIT 0x08 /* JIT disabled for this function. */
#define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */
/* Only used during parsing. */
#define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */
#define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */
/* Top bits used for counting created closures. */
#define PROTO_CLCOUNT 0x20 /* Base of saturating 3 bit counter. */
#define PROTO_CLC_BITS 3
#define PROTO_CLC_POLY (3 * PROTO_CLCOUNT) /* Polymorphic threshold. */
#define PROTO_UV_LOCAL 0x8000 /* Upvalue for local slot. */
#define PROTO_UV_IMMUTABLE 0x4000 /* Immutable upvalue. */
#define proto_kgc(pt, idx) \
check_exp((uintptr_t)(intptr_t)(idx) >= (uintptr_t) - (intptr_t)(pt)->sizekgc, \
gcref(mref((pt)->k, GCRef)[(idx)]))
#define proto_knumtv(pt, idx) \
check_exp((uintptr_t)(idx) < (pt)->sizekn, &mref((pt)->k, TValue)[(idx)])
#define proto_bc(pt) ((BCIns *)((char *)(pt) + sizeof(GCproto)))
#define proto_bcpos(pt, pc) ((BCPos)((pc)-proto_bc(pt)))
#define proto_uv(pt) (mref((pt)->uv, uint16_t))
#define proto_chunkname(pt) (strref(BPF_PROBE_READ_USER(pt, chunkname)))
#define proto_chunknamestr(pt) (strdata(proto_chunkname((pt))))
#define proto_lineinfo(pt) (mref((pt)->lineinfo, const void))
#define proto_uvinfo(pt) (mref((pt)->uvinfo, const uint8_t))
#define proto_varinfo(pt) (mref((pt)->varinfo, const uint8_t))
/* -- Upvalue object ------------------------------------------------------ */
typedef struct GCupval
{
GCHeader;
uint8_t closed; /* Set if closed (i.e. uv->v == &uv->u.value). */
uint8_t immutable; /* Immutable value. */
union
{
TValue tv; /* If closed: the value itself. */
struct
{ /* If open: double linked list, anchored at thread. */
GCRef prev;
GCRef next;
};
};
MRef v; /* Points to stack slot (open) or above (closed). */
uint32_t dhash; /* Disambiguation hash: dh1 != dh2 => cannot alias. */
} GCupval;
#define uvprev(uv_) (&gcref((uv_)->prev)->uv)
#define uvnext(uv_) (&gcref((uv_)->next)->uv)
#define uvval(uv_) (mref((uv_)->v, TValue))
/* GC header for generic access to common fields of GC objects. */
typedef struct GChead
{
GCHeader;
uint8_t unused1;
uint8_t unused2;
GCRef env;
GCRef gclist;
GCRef metatable;
} GChead;
/* -- Function object (closures) ------------------------------------------ */
/* Common header for functions. env should be at same offset in GCudata. */
#define GCfuncHeader \
GCHeader; \
uint8_t ffid; \
uint8_t nupvalues; \
GCRef env; \
GCRef gclist; \
MRef pc
typedef struct GCfuncC
{
GCfuncHeader;
lua_CFunction f; /* C function to be called. */
TValue upvalue[1]; /* Array of upvalues (TValue). */
} GCfuncC;
typedef struct GCfuncL
{
GCfuncHeader;
GCRef uvptr[1]; /* Array of _pointers_ to upvalue objects (GCupval). */
} GCfuncL;
typedef union GCfunc
{
GCfuncC c;
GCfuncL l;
} GCfunc;
#define FF_LUA 0
#define FF_C 1
#define isluafunc(fn) (BPF_PROBE_READ_USER(fn, c.ffid) == FF_LUA)
#define iscfunc(fn) (BPF_PROBE_READ_USER(fn, c.ffid) == FF_C)
#define isffunc(fn) (BPF_PROBE_READ_USER(fn, c.ffid) > FF_C)
#define funcproto(fn) \
check_exp(isluafunc(fn), (GCproto *)(mref(BPF_PROBE_READ_USER((fn), l.pc), char) - sizeof(GCproto)))
#define sizeCfunc(n) (sizeof(GCfuncC) - sizeof(TValue) + sizeof(TValue) * (n))
#define sizeLfunc(n) (sizeof(GCfuncL) - sizeof(GCRef) + sizeof(GCRef) * (n))
typedef struct GCtab
{
GCHeader;
uint8_t nomm; /* Negative cache for fast metamethods. */
char colo; /* Array colocation. */
MRef array; /* Array part. */
GCRef gclist;
GCRef metatable; /* Must be at same offset in GCudata. */
MRef node; /* Hash part. */
uint32_t asize; /* Size of array part (keys [0, asize-1]). */
uint32_t hmask; /* Hash part mask (size of hash part - 1). */
#if LJ_GC64
MRef freetop; /* Top of free elements. */
#endif
} GCtab;
#define sizetabcolo(n) ((n) * sizeof(TValue) + sizeof(GCtab))
#define tabref(r) (&gcref((r))->tab)
#define noderef(r) (mref((r), Node))
#define nextnode(n) (mref((n)->next, Node))
#if LJ_GC64
#define getfreetop(t, n) (noderef((t)->freetop))
#define setfreetop(t, n, v) (setmref((t)->freetop, (v)))
#else
#define getfreetop(t, n) (noderef((n)->freetop))
#define setfreetop(t, n, v) (setmref((n)->freetop, (v)))
#endif
typedef union GCobj
{
GChead gch;
GCstr str;
GCupval uv;
lua_State th;
GCproto pt;
GCfunc fn;
GCcdata cd;
GCtab tab;
GCudata ud;
} GCobj;
/* Macros to convert a GCobj pointer into a specific value. */
#define gco2str(o) check_exp((o)->gch.gct == ~LJ_TSTR, &(o)->str)
#define gco2uv(o) check_exp((o)->gch.gct == ~LJ_TUPVAL, &(o)->uv)
#define gco2th(o) check_exp((o)->gch.gct == ~LJ_TTHREAD, &(o)->th)
#define gco2pt(o) check_exp((o)->gch.gct == ~LJ_TPROTO, &(o)->pt)
#define gco2func(o) check_exp((o)->gch.gct == ~LJ_TFUNC, &(o)->fn)
#define gco2cd(o) check_exp((o)->gch.gct == ~LJ_TCDATA, &(o)->cd)
#define gco2tab(o) check_exp((o)->gch.gct == ~LJ_TTAB, &(o)->tab)
#define gco2ud(o) check_exp((o)->gch.gct == ~LJ_TUDATA, &(o)->ud)
/* Macro to convert any collectable object into a GCobj pointer. */
#define obj2gco(v) ((GCobj *)(v))
#if LJ_GC64
#define gcval(o) ((GCobj *)(gcrefu(BPF_PROBE_READ_USER(o, gcr)) & LJ_GCVMASK))
#else
#define gcval(o) (gcref((o)->gcr))
#endif
/* -- Lua stack frame ----------------------------------------------------- */
/* Frame type markers in LSB of PC (4-byte aligned) or delta (8-byte aligned:
**
** PC 00 Lua frame
** delta 001 C frame
** delta 010 Continuation frame
** delta 011 Lua vararg frame
** delta 101 cpcall() frame
** delta 110 ff pcall() frame
** delta 111 ff pcall() frame with active hook
*/
enum
{
FRAME_LUA,
FRAME_C,
FRAME_CONT,
FRAME_VARG,
FRAME_LUAP,
FRAME_CP,
FRAME_PCALL,
FRAME_PCALLH
};
#define FRAME_TYPE 3
#define FRAME_P 4
#define FRAME_TYPEP (FRAME_TYPE | FRAME_P)
/* Macros to access and modify Lua frames. */
#if LJ_FR2
/* Two-slot frame info, required for 64 bit PC/GCRef:
**
** base-2 base-1 | base base+1 ...
** [func PC/delta/ft] | [slots ...]
** ^-- frame | ^-- base ^-- top
**
** Continuation frames:
**
** base-4 base-3 base-2 base-1 | base base+1 ...
** [cont PC ] [func PC/delta/ft] | [slots ...]
** ^-- frame | ^-- base ^-- top
*/
#define frame_gc(f) (gcval((f)-1))
#define frame_ftsz(f) ((ptrdiff_t)BPF_PROBE_READ_USER(frame, ftsz))
#define frame_pc(f) ((const BCIns *)frame_ftsz(f))
#define setframe_ftsz(f, sz) ((f)->ftsz = (sz))
#define setframe_pc(f, pc) ((f)->ftsz = (int64_t)(intptr_t)(pc))
#else
/* One-slot frame info, sufficient for 32 bit PC/GCRef:
**
** base-1 | base base+1 ...
** lo hi |
** [func | PC/delta/ft] | [slots ...]
** ^-- frame | ^-- base ^-- top
**
** Continuation frames:
**
** base-2 base-1 | base base+1 ...
** lo hi lo hi |
** [cont | PC] [func | PC/delta/ft] | [slots ...]
** ^-- frame | ^-- base ^-- top
*/
#define frame_gc(f) (gcref((f)->fr.func))
#define frame_ftsz(f) ((ptrdiff_t)BPF_PROBE_READ_USER(f, fr.tp.ftsz))
#define frame_pc(f) (mref((f)->fr.tp.pcr, const BCIns))
#define setframe_gc(f, p, tp) (setgcref((f)->fr.func, (p)), UNUSED(tp))
#define setframe_ftsz(f, sz) ((f)->fr.tp.ftsz = (int32_t)(sz))
#define setframe_pc(f, pc) (setmref((f)->fr.tp.pcr, (pc)))
#endif
#define frame_type(f) (frame_ftsz(f) & FRAME_TYPE)
#define frame_typep(f) (frame_ftsz(f) & FRAME_TYPEP)
#define frame_islua(f) (frame_type(f) == FRAME_LUA)
#define frame_isc(f) (frame_type(f) == FRAME_C)
#define frame_iscont(f) (frame_typep(f) == FRAME_CONT)
#define frame_isvarg(f) (frame_typep(f) == FRAME_VARG)
#define frame_ispcall(f) ((frame_ftsz(f) & 6) == FRAME_PCALL)
#define frame_func(f) (&frame_gc(f)->fn)
#define frame_delta(f) (frame_ftsz(f) >> 3)
#define frame_sized(f) (frame_ftsz(f) & ~FRAME_TYPEP)
enum
{
LJ_CONT_TAILCALL,
LJ_CONT_FFI_CALLBACK
}; /* Special continuations. */
#define frame_iscont_fficb(f) \
(LJ_HASFFI && frame_contv(f) == LJ_CONT_FFI_CALLBACK)
static __always_inline BCIns frame_pc_prev(const BCIns *bcins)
{
const BCIns bcins_prev;
bpf_probe_read_user((void *)&bcins_prev, sizeof(bcins_prev), bcins - 1);
return bcins_prev;
}
#define frame_prevl(f) ((f) - (1 + LJ_FR2 + bc_a(frame_pc_prev(frame_pc(f)))))
#define frame_prevd(f) ((TValue *)((char *)(f)-frame_sized(f)))
#define frame_prev(f) (frame_islua(f) ? frame_prevl(f) : frame_prevd(f))
/* -- State objects ------------------------------------------------------- */
/* VM states. */
enum
{
LJ_VMST_INTERP, /* Interpreter. */
LJ_VMST_C, /* C function. */
LJ_VMST_GC, /* Garbage collector. */
LJ_VMST_EXIT, /* Trace exit handler. */
LJ_VMST_RECORD, /* Trace recorder. */
LJ_VMST_OPT, /* Optimizer. */
LJ_VMST_ASM, /* Assembler. */
LJ_VMST__MAX
};
#define setvmstate(g, st) ((g)->vmstate = ~LJ_VMST_##st)
/* Metamethods. ORDER MM */
#ifdef LJ_HASFFI
#define MMDEF_FFI(_) _(new)
#else
#define MMDEF_FFI(_)
#endif
#if LJ_52 || LJ_HASFFI
#define MMDEF_PAIRS(_) _(pairs) _(ipairs)
#else
#define MMDEF_PAIRS(_)
#define MM_pairs 255
#define MM_ipairs 255
#endif
#define MMDEF(_) \
_(index) \
_(newindex) _(gc) _(mode) _(eq) _(len) /* Only the above (fast) metamethods are negative cached (max. 8). */ \
_(lt) _(le) _(concat) _(call) /* The following must be in ORDER ARITH. */ \
_(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm) /* The following are used in the standard libraries. */ \
_(metatable) _(tostring) MMDEF_FFI(_) MMDEF_PAIRS(_)
typedef enum
{
#define MMENUM(name) MM_##name,
MMDEF(MMENUM)
#undef MMENUM
MM__MAX,
MM____ = MM__MAX,
MM_FAST = MM_len
} MMS;
/* GC root IDs. */
typedef enum
{
GCROOT_MMNAME, /* Metamethod names. */
GCROOT_MMNAME_LAST = GCROOT_MMNAME + MM__MAX - 1,
GCROOT_BASEMT, /* Metatables for base types. */
GCROOT_BASEMT_NUM = GCROOT_BASEMT + ~LJ_TNUMX,
GCROOT_IO_INPUT, /* Userdata for default I/O input file. */
GCROOT_IO_OUTPUT, /* Userdata for default I/O output file. */
GCROOT_MAX
} GCRootID;
/* Garbage collector state. */
typedef struct GCState
{
GCSize total; /* Memory currently allocated. */
GCSize threshold; /* Memory threshold. */
uint8_t currentwhite; /* Current white color. */
uint8_t state; /* GC state. */
uint8_t nocdatafin; /* No cdata finalizer called. */
#if LJ_64
uint8_t lightudnum; /* Number of lightuserdata segments - 1. */
#else
uint8_t unused1;
#endif
MSize sweepstr; /* Sweep position in string table. */
GCRef root; /* List of all collectable objects. */
MRef sweep; /* Sweep position in root list. */
GCRef gray; /* List of gray objects. */
GCRef grayagain; /* List of objects for atomic traversal. */
GCRef weak; /* List of weak tables (to be cleared). */
GCRef mmudata; /* List of userdata (to be finalized). */
GCSize debt; /* Debt (how much GC is behind schedule). */
GCSize estimate; /* Estimate of memory actually in use. */
MSize stepmul; /* Incremental GC step granularity. */
MSize pause; /* Pause between successive GC cycles. */
#if LJ_64
MRef lightudseg; /* Upper bits of lightuserdata segments. */
#endif
} GCState;
/* thread status */
#define LUA_OK 0
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRERR 5
#endif