mirror of
https://github.com/lua/lua
synced 2024-11-25 06:09:36 +03:00
e2cc179454
The generational mode also uses the parameters for the incremental mode in its major collections, so it should be easy to change those parameters without having to change the GC mode.
408 lines
15 KiB
C
408 lines
15 KiB
C
/*
|
|
** $Id: lstate.h $
|
|
** Global State
|
|
** See Copyright Notice in lua.h
|
|
*/
|
|
|
|
#ifndef lstate_h
|
|
#define lstate_h
|
|
|
|
#include "lua.h"
|
|
|
|
|
|
/* Some header files included here need this definition */
|
|
typedef struct CallInfo CallInfo;
|
|
|
|
|
|
#include "lobject.h"
|
|
#include "ltm.h"
|
|
#include "lzio.h"
|
|
|
|
|
|
/*
|
|
** Some notes about garbage-collected objects: All objects in Lua must
|
|
** be kept somehow accessible until being freed, so all objects always
|
|
** belong to one (and only one) of these lists, using field 'next' of
|
|
** the 'CommonHeader' for the link:
|
|
**
|
|
** 'allgc': all objects not marked for finalization;
|
|
** 'finobj': all objects marked for finalization;
|
|
** 'tobefnz': all objects ready to be finalized;
|
|
** 'fixedgc': all objects that are not to be collected (currently
|
|
** only small strings, such as reserved words).
|
|
**
|
|
** For the generational collector, some of these lists have marks for
|
|
** generations. Each mark points to the first element in the list for
|
|
** that particular generation; that generation goes until the next mark.
|
|
**
|
|
** 'allgc' -> 'survival': new objects;
|
|
** 'survival' -> 'old': objects that survived one collection;
|
|
** 'old1' -> 'reallyold': objects that became old in last collection;
|
|
** 'reallyold' -> NULL: objects old for more than one cycle.
|
|
**
|
|
** 'finobj' -> 'finobjsur': new objects marked for finalization;
|
|
** 'finobjsur' -> 'finobjold1': survived """";
|
|
** 'finobjold1' -> 'finobjrold': just old """";
|
|
** 'finobjrold' -> NULL: really old """".
|
|
**
|
|
** All lists can contain elements older than their main ages, due
|
|
** to 'luaC_checkfinalizer' and 'udata2finalize', which move
|
|
** objects between the normal lists and the "marked for finalization"
|
|
** lists. Moreover, barriers can age young objects in young lists as
|
|
** OLD0, which then become OLD1. However, a list never contains
|
|
** elements younger than their main ages.
|
|
**
|
|
** The generational collector also uses a pointer 'firstold1', which
|
|
** points to the first OLD1 object in the list. It is used to optimize
|
|
** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
|
|
** and 'reallyold', but often the list has no OLD1 objects or they are
|
|
** after 'old1'.) Note the difference between it and 'old1':
|
|
** 'firstold1': no OLD1 objects before this point; there can be all
|
|
** ages after it.
|
|
** 'old1': no objects younger than OLD1 after this point.
|
|
*/
|
|
|
|
/*
|
|
** Moreover, there is another set of lists that control gray objects.
|
|
** These lists are linked by fields 'gclist'. (All objects that
|
|
** can become gray have such a field. The field is not the same
|
|
** in all objects, but it always has this name.) Any gray object
|
|
** must belong to one of these lists, and all objects in these lists
|
|
** must be gray (with two exceptions explained below):
|
|
**
|
|
** 'gray': regular gray objects, still waiting to be visited.
|
|
** 'grayagain': objects that must be revisited at the atomic phase.
|
|
** That includes
|
|
** - black objects got in a write barrier;
|
|
** - all kinds of weak tables during propagation phase;
|
|
** - all threads.
|
|
** 'weak': tables with weak values to be cleared;
|
|
** 'ephemeron': ephemeron tables with white->white entries;
|
|
** 'allweak': tables with weak keys and/or weak values to be cleared.
|
|
**
|
|
** The exceptions to that "gray rule" are:
|
|
** - TOUCHED2 objects in generational mode stay in a gray list (because
|
|
** they must be visited again at the end of the cycle), but they are
|
|
** marked black because assignments to them must activate barriers (to
|
|
** move them back to TOUCHED1).
|
|
** - Open upvales are kept gray to avoid barriers, but they stay out
|
|
** of gray lists. (They don't even have a 'gclist' field.)
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
** About 'nCcalls': This count has two parts: the lower 16 bits counts
|
|
** the number of recursive invocations in the C stack; the higher
|
|
** 16 bits counts the number of non-yieldable calls in the stack.
|
|
** (They are together so that we can change and save both with one
|
|
** instruction.)
|
|
*/
|
|
|
|
|
|
/* true if this thread does not have non-yieldable calls in the stack */
|
|
#define yieldable(L) (((L)->nCcalls & 0xffff0000) == 0)
|
|
|
|
/* real number of C calls */
|
|
#define getCcalls(L) ((L)->nCcalls & 0xffff)
|
|
|
|
|
|
/* Increment the number of non-yieldable calls */
|
|
#define incnny(L) ((L)->nCcalls += 0x10000)
|
|
|
|
/* Decrement the number of non-yieldable calls */
|
|
#define decnny(L) ((L)->nCcalls -= 0x10000)
|
|
|
|
/* Non-yieldable call increment */
|
|
#define nyci (0x10000 | 1)
|
|
|
|
|
|
|
|
|
|
struct lua_longjmp; /* defined in ldo.c */
|
|
|
|
|
|
/*
|
|
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
|
|
** is thread safe
|
|
*/
|
|
#if !defined(l_signalT)
|
|
#include <signal.h>
|
|
#define l_signalT sig_atomic_t
|
|
#endif
|
|
|
|
|
|
/*
|
|
** Extra stack space to handle TM calls and some other extras. This
|
|
** space is not included in 'stack_last'. It is used only to avoid stack
|
|
** checks, either because the element will be promptly popped or because
|
|
** there will be a stack check soon after the push. Function frames
|
|
** never use this extra space, so it does not need to be kept clean.
|
|
*/
|
|
#define EXTRA_STACK 5
|
|
|
|
|
|
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
|
|
|
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
|
|
|
|
|
|
/* kinds of Garbage Collection */
|
|
#define KGC_INC 0 /* incremental gc */
|
|
#define KGC_GENMINOR 1 /* generational gc in minor (regular) mode */
|
|
#define KGC_GENMAJOR 2 /* generational in major mode */
|
|
|
|
|
|
typedef struct stringtable {
|
|
TString **hash; /* array of buckets (linked lists of strings) */
|
|
int nuse; /* number of elements */
|
|
int size; /* number of buckets */
|
|
} stringtable;
|
|
|
|
|
|
/*
|
|
** Information about a call.
|
|
** About union 'u':
|
|
** - field 'l' is used only for Lua functions;
|
|
** - field 'c' is used only for C functions.
|
|
** About union 'u2':
|
|
** - field 'funcidx' is used only by C functions while doing a
|
|
** protected call;
|
|
** - field 'nyield' is used only while a function is "doing" an
|
|
** yield (from the yield until the next resume);
|
|
** - field 'nres' is used only while closing tbc variables when
|
|
** returning from a function;
|
|
** - field 'transferinfo' is used only during call/returnhooks,
|
|
** before the function starts or after it ends.
|
|
*/
|
|
struct CallInfo {
|
|
StkIdRel func; /* function index in the stack */
|
|
StkIdRel top; /* top for this function */
|
|
struct CallInfo *previous, *next; /* dynamic call link */
|
|
union {
|
|
struct { /* only for Lua functions */
|
|
const Instruction *savedpc;
|
|
volatile l_signalT trap; /* function is tracing lines/counts */
|
|
int nextraargs; /* # of extra arguments in vararg functions */
|
|
} l;
|
|
struct { /* only for C functions */
|
|
lua_KFunction k; /* continuation in case of yields */
|
|
ptrdiff_t old_errfunc;
|
|
lua_KContext ctx; /* context info. in case of yields */
|
|
} c;
|
|
} u;
|
|
union {
|
|
int funcidx; /* called-function index */
|
|
int nyield; /* number of values yielded */
|
|
int nres; /* number of values returned */
|
|
struct { /* info about transferred values (for call/return hooks) */
|
|
unsigned short ftransfer; /* offset of first value transferred */
|
|
unsigned short ntransfer; /* number of values transferred */
|
|
} transferinfo;
|
|
} u2;
|
|
short nresults; /* expected number of results from this function */
|
|
unsigned short callstatus;
|
|
};
|
|
|
|
|
|
/*
|
|
** Bits in CallInfo status
|
|
*/
|
|
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
|
|
#define CIST_C (1<<1) /* call is running a C function */
|
|
#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
|
|
#define CIST_HOOKED (1<<3) /* call is running a debug hook */
|
|
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
|
|
#define CIST_TAIL (1<<5) /* call was tail called */
|
|
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
|
#define CIST_FIN (1<<7) /* function "called" a finalizer */
|
|
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
|
|
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
|
|
/* Bits 10-12 are used for CIST_RECST (see below) */
|
|
#define CIST_RECST 10
|
|
#if defined(LUA_COMPAT_LT_LE)
|
|
#define CIST_LEQ (1<<13) /* using __lt for __le */
|
|
#endif
|
|
|
|
|
|
/*
|
|
** Field CIST_RECST stores the "recover status", used to keep the error
|
|
** status while closing to-be-closed variables in coroutines, so that
|
|
** Lua can correctly resume after an yield from a __close method called
|
|
** because of an error. (Three bits are enough for error status.)
|
|
*/
|
|
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
|
|
#define setcistrecst(ci,st) \
|
|
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
|
|
((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
|
|
| ((st) << CIST_RECST)))
|
|
|
|
|
|
/* active function is a Lua function */
|
|
#define isLua(ci) (!((ci)->callstatus & CIST_C))
|
|
|
|
/* call is running Lua code (not a hook) */
|
|
#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED)))
|
|
|
|
/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
|
|
#define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v))
|
|
#define getoah(st) ((st) & CIST_OAH)
|
|
|
|
|
|
/*
|
|
** 'global state', shared by all threads of this state
|
|
*/
|
|
typedef struct global_State {
|
|
lua_Alloc frealloc; /* function to reallocate memory */
|
|
void *ud; /* auxiliary data to 'frealloc' */
|
|
lu_mem totalbytes; /* number of bytes currently allocated */
|
|
l_obj totalobjs; /* total number of objects allocated + GCdebt */
|
|
l_obj GCdebt; /* objects counted but not yet allocated */
|
|
l_obj marked; /* number of objects marked in a GC cycle */
|
|
l_obj GCmajorminor; /* auxiliar counter to control major-minor shifts */
|
|
stringtable strt; /* hash table for strings */
|
|
TValue l_registry;
|
|
TValue nilvalue; /* a nil value */
|
|
unsigned int seed; /* randomized seed for hashes */
|
|
lu_byte gcparams[LUA_GCPN];
|
|
lu_byte currentwhite;
|
|
lu_byte gcstate; /* state of garbage collector */
|
|
lu_byte gckind; /* kind of GC running */
|
|
lu_byte gcstopem; /* stops emergency collections */
|
|
lu_byte gcstp; /* control whether GC is running */
|
|
lu_byte gcemergency; /* true if this is an emergency collection */
|
|
GCObject *allgc; /* list of all collectable objects */
|
|
GCObject **sweepgc; /* current position of sweep in list */
|
|
GCObject *finobj; /* list of collectable objects with finalizers */
|
|
GCObject *gray; /* list of gray objects */
|
|
GCObject *grayagain; /* list of objects to be traversed atomically */
|
|
GCObject *weak; /* list of tables with weak values */
|
|
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
|
|
GCObject *allweak; /* list of all-weak tables */
|
|
GCObject *tobefnz; /* list of userdata to be GC */
|
|
GCObject *fixedgc; /* list of objects not to be collected */
|
|
/* fields for generational collector */
|
|
GCObject *survival; /* start of objects that survived one GC cycle */
|
|
GCObject *old1; /* start of old1 objects */
|
|
GCObject *reallyold; /* objects more than one cycle old ("really old") */
|
|
GCObject *firstold1; /* first OLD1 object in the list (if any) */
|
|
GCObject *finobjsur; /* list of survival objects with finalizers */
|
|
GCObject *finobjold1; /* list of old1 objects with finalizers */
|
|
GCObject *finobjrold; /* list of really old objects with finalizers */
|
|
struct lua_State *twups; /* list of threads with open upvalues */
|
|
lua_CFunction panic; /* to be called in unprotected errors */
|
|
struct lua_State *mainthread;
|
|
TString *memerrmsg; /* message for memory-allocation errors */
|
|
TString *tmname[TM_N]; /* array with tag-method names */
|
|
struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
|
|
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
|
|
lua_WarnFunction warnf; /* warning function */
|
|
void *ud_warn; /* auxiliary data to 'warnf' */
|
|
} global_State;
|
|
|
|
|
|
/*
|
|
** 'per thread' state
|
|
*/
|
|
struct lua_State {
|
|
CommonHeader;
|
|
lu_byte status;
|
|
lu_byte allowhook;
|
|
unsigned short nci; /* number of items in 'ci' list */
|
|
StkIdRel top; /* first free slot in the stack */
|
|
global_State *l_G;
|
|
CallInfo *ci; /* call info for current function */
|
|
StkIdRel stack_last; /* end of stack (last element + 1) */
|
|
StkIdRel stack; /* stack base */
|
|
UpVal *openupval; /* list of open upvalues in this stack */
|
|
StkIdRel tbclist; /* list of to-be-closed variables */
|
|
GCObject *gclist;
|
|
struct lua_State *twups; /* list of threads with open upvalues */
|
|
struct lua_longjmp *errorJmp; /* current error recover point */
|
|
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
|
volatile lua_Hook hook;
|
|
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
|
l_uint32 nCcalls; /* number of nested (non-yieldable | C) calls */
|
|
int oldpc; /* last pc traced */
|
|
int basehookcount;
|
|
int hookcount;
|
|
volatile l_signalT hookmask;
|
|
};
|
|
|
|
|
|
#define G(L) (L->l_G)
|
|
|
|
/*
|
|
** 'g->nilvalue' being a nil value flags that the state was completely
|
|
** build.
|
|
*/
|
|
#define completestate(g) ttisnil(&g->nilvalue)
|
|
|
|
|
|
/*
|
|
** Union of all collectable objects (only for conversions)
|
|
** ISO C99, 6.5.2.3 p.5:
|
|
** "if a union contains several structures that share a common initial
|
|
** sequence [...], and if the union object currently contains one
|
|
** of these structures, it is permitted to inspect the common initial
|
|
** part of any of them anywhere that a declaration of the complete type
|
|
** of the union is visible."
|
|
*/
|
|
union GCUnion {
|
|
GCObject gc; /* common header */
|
|
struct TString ts;
|
|
struct Udata u;
|
|
union Closure cl;
|
|
struct Table h;
|
|
struct Proto p;
|
|
struct lua_State th; /* thread */
|
|
struct UpVal upv;
|
|
};
|
|
|
|
|
|
/*
|
|
** ISO C99, 6.7.2.1 p.14:
|
|
** "A pointer to a union object, suitably converted, points to each of
|
|
** its members [...], and vice versa."
|
|
*/
|
|
#define cast_u(o) cast(union GCUnion *, (o))
|
|
|
|
/* macros to convert a GCObject into a specific value */
|
|
#define gco2ts(o) \
|
|
check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
|
|
#define gco2u(o) check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u))
|
|
#define gco2lcl(o) check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l))
|
|
#define gco2ccl(o) check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c))
|
|
#define gco2cl(o) \
|
|
check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
|
|
#define gco2t(o) check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h))
|
|
#define gco2p(o) check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p))
|
|
#define gco2th(o) check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th))
|
|
#define gco2upv(o) check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv))
|
|
|
|
|
|
/*
|
|
** macro to convert a Lua object into a GCObject
|
|
** (The access to 'tt' tries to ensure that 'v' is actually a Lua object.)
|
|
*/
|
|
#define obj2gco(v) check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))
|
|
|
|
|
|
/* actual number of total objects allocated */
|
|
#define gettotalobjs(g) ((g)->totalobjs - (g)->GCdebt)
|
|
|
|
|
|
LUAI_FUNC void luaE_setdebt (global_State *g, l_obj debt);
|
|
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
|
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
|
LUAI_FUNC void luaE_checkcstack (lua_State *L);
|
|
LUAI_FUNC void luaE_incCstack (lua_State *L);
|
|
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
|
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
|
|
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
|
|
|
|
|
|
#endif
|
|
|