luau-src 0.3.0

Luau source code bindings
Documentation
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details
#pragma once

#include "lobject.h"
#include "ltm.h"

/* table of globals */
#define gt(L) (&L->l_gt)


/* registry */
#define registry(L) (&L->global->registry)


/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5


#define BASIC_CI_SIZE 8


#define BASIC_STACK_SIZE (2 * LUA_MINSTACK)


// clang-format off
typedef struct stringtable
{

    GCObject** hash;
    uint32_t nuse; /* number of elements */
    int size;
} stringtable;
// clang-format on

/*
** informations about a call
**
** the general Lua stack frame structure is as follows:
** - each function gets a stack frame, with function "registers" being stack slots on the frame
** - function arguments are associated with registers 0+
** - function locals and temporaries follow after; usually locals are a consecutive block per scope, and temporaries are allocated after this, but
*this is up to the compiler
**
** when function doesn't have varargs, the stack layout is as follows:
** ^ (func) ^^ [fixed args] [locals + temporaries]
** where ^ is the 'func' pointer in CallInfo struct, and ^^ is the 'base' pointer (which is what registers are relative to)
**
** when function *does* have varargs, the stack layout is more complex - the runtime has to copy the fixed arguments so that the 0+ addressing still
*works as follows:
** ^ (func) [fixed args] [varargs] ^^ [fixed args] [locals + temporaries]
**
** computing the sizes of these individual blocks works as follows:
** - the number of fixed args is always matching the `numparams` in a function's Proto object; runtime adds `nil` during the call execution as
*necessary
** - the number of variadic args can be computed by evaluating (ci->base - ci->func - 1 - numparams)
**
** the CallInfo structures are allocated as an array, with each subsequent call being *appended* to this array (so if f calls g, CallInfo for g
*immediately follows CallInfo for f)
** the `nresults` field in CallInfo is set by the caller to tell the function how many arguments the caller is expecting on the stack after the
*function returns
** the `flags` field in CallInfo contains internal execution flags that are important for pcall/etc, see LUA_CALLINFO_*
*/
// clang-format off
typedef struct CallInfo
{

    StkId base;    /* base for this function */
    StkId func;    /* function index in the stack */
    StkId top;     /* top for this function */
    const Instruction* savedpc;

    int nresults;       /* expected number of results from this function */
    unsigned int flags; /* call frame flags, see LUA_CALLINFO_* */
} CallInfo;
// clang-format on

#define LUA_CALLINFO_RETURN (1 << 0) /* should the interpreter return after returning from this callinfo? first frame must have this set */

#define LUA_CALLINFO_HANDLE (1 << 1) /* should the error thrown during execution get handled by continuation from this callinfo? func must be C */


#define curr_func(L) (clvalue(L->ci->func))

#define ci_func(ci) (clvalue((ci)->func))

#define f_isLua(ci) (!ci_func(ci)->isC)

#define isLua(ci) (ttisfunction((ci)->func) && f_isLua(ci))


struct GCCycleStats
{
    size_t heapgoalsizebytes = 0;
    size_t heaptriggersizebytes = 0;

    double waittime = 0.0; // time from end of the last cycle to the start of a new one

    double starttimestamp = 0.0;
    double endtimestamp = 0.0;

    double marktime = 0.0;

    double atomicstarttimestamp = 0.0;
    size_t atomicstarttotalsizebytes = 0;
    double atomictime = 0.0;

    double sweeptime = 0.0;

    size_t markitems = 0;
    size_t sweepitems = 0;

    size_t assistwork = 0;
    size_t explicitwork = 0;

    size_t endtotalsizebytes = 0;
};

// data for proportional-integral controller of heap trigger value
struct GCHeapTriggerStats
{
    static const unsigned termcount = 32;
    int32_t terms[termcount] = {0};
    uint32_t termpos = 0;
    int32_t integral = 0;
};

struct GCStats
{
    double stepexplicittimeacc = 0.0;
    double stepassisttimeacc = 0.0;

    // when cycle is completed, last cycle values are updated
    uint64_t completedcycles = 0;

    GCCycleStats lastcycle;
    GCCycleStats currcycle;

    // only step count and their time is accumulated
    GCCycleStats cyclestatsacc;

    GCHeapTriggerStats triggerstats;
};

/*
** `global state', shared by all threads of this state
*/
// clang-format off
typedef struct global_State
{
    stringtable strt; /* hash table for strings */


    lua_Alloc frealloc;   /* function to reallocate memory */
    void* ud;            /* auxiliary data to `frealloc' */


    uint8_t currentwhite;
    uint8_t gcstate; /* state of garbage collector */


    int sweepstrgc;      /* position of sweep in `strt' */
    GCObject* rootgc;    /* list of all collectable objects */
    GCObject** sweepgc;  /* position of sweep in `rootgc' */
    GCObject* gray;      /* list of gray objects */
    GCObject* grayagain; /* list of objects to be traversed atomically */
    GCObject* weak;     /* list of weak tables (to be cleared) */

    GCObject* strbufgc; // list of all string buffer objects


    size_t GCthreshold;                       // when totalbytes > GCthreshold; run GC step
    size_t totalbytes;                        // number of bytes currently allocated
    int gcgoal;                               // see LUAI_GCGOAL
    int gcstepmul;                            // see LUAI_GCSTEPMUL
    int gcstepsize;                          // see LUAI_GCSTEPSIZE

    struct lua_Page* freepages[LUA_SIZECLASSES]; /* free page linked list for each size class */

    size_t memcatbytes[LUA_MEMORY_CATEGORIES]; /* total amount of memory used by each memory category */


    struct lua_State* mainthread;
    UpVal uvhead;                                    /* head of double-linked list of all open upvalues */
    struct Table* mt[LUA_T_COUNT];                   /* metatables for basic types */
    TString* ttname[LUA_T_COUNT];       /* names for basic types */
    TString* tmname[TM_N];             /* array with tag-method names */

    TValue registry; /* registry table, used by lua_ref and LUA_REGISTRYINDEX */
    int registryfree; /* next free slot in registry */

    struct lua_jmpbuf* errorjmp; /* jump buffer data for longjmp-style error handling */

    uint64_t rngstate; /* PCG random number generator state */
    uint64_t ptrenckey[4]; /* pointer encoding key for display */

    void (*udatagc[LUA_UTAG_LIMIT])(void*);          /* for each userdata tag, a gc callback to be called immediately before freeing memory */

    lua_Callbacks cb;

    GCStats gcstats;

} global_State;
// clang-format on

/*
** `per thread' state
*/
// clang-format off
struct lua_State
{
    CommonHeader;
    uint8_t status;

    uint8_t activememcat; /* memory category that is used for new GC object allocations */
    uint8_t stackstate;

    bool singlestep; /* call debugstep hook after each instruction */


    StkId top;                                        /* first free slot in the stack */
    StkId base;                                       /* base of current function */
    global_State* global;
    CallInfo* ci;                                     /* call info for current function */
    StkId stack_last;                                 /* last free slot in the stack */
    StkId stack;                                     /* stack base */


    CallInfo* end_ci;                          /* points after end of ci array*/
    CallInfo* base_ci;                        /* array of CallInfo's */


    int stacksize;
    int size_ci;                              /* size of array `base_ci' */


    unsigned short nCcalls;     /* number of nested C calls */
    unsigned short baseCcalls; /* nested C calls when resuming coroutine */

    int cachedslot;    /* when table operations or INDEX/NEWINDEX is invoked from Luau, what is the expected slot for lookup? */


    TValue l_gt;            /* table of globals */
    TValue env;             /* temporary place for environments */
    GCObject* openupval;    /* list of open upvalues in this stack */
    GCObject* gclist;

    TString* namecall; /* when invoked from Luau using NAMECALL, what method do we need to invoke? */

    void* userdata;
};
// clang-format on

/*
** Union of all collectible objects
*/
union GCObject
{
    GCheader gch;
    struct TString ts;
    struct Udata u;
    struct Closure cl;
    struct Table h;
    struct Proto p;
    struct UpVal uv;
    struct lua_State th; /* thread */
};

/* macros to convert a GCObject into a specific value */
#define gco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts))

#define gco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))

#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl))

#define gco2h(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))

#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))

#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))

#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))


/* macro to convert any Lua object into a GCObject */
#define obj2gco(v) check_exp(iscollectable(v), cast_to(GCObject*, (v) + 0))


LUAI_FUNC lua_State* luaE_newthread(lua_State* L);
LUAI_FUNC void luaE_freethread(lua_State* L, lua_State* L1);