ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

lj_func.c (7860B)


      1 /*
      2 ** Function handling (prototypes, functions and upvalues).
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 **
      5 ** Upvalue handling rewrite and closure lifting.
      6 ** Copyright (C) 2014 Karel Tuma. See Copyright Notice in luajit.h
      7 **
      8 ** Portions taken verbatim or adapted from the Lua interpreter.
      9 ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
     10 */
     11 
     12 #define lj_func_c
     13 #define LUA_CORE
     14 
     15 #include "lj_obj.h"
     16 #include "lj_gc.h"
     17 #include "lj_func.h"
     18 #include "lj_trace.h"
     19 #include "lj_vm.h"
     20 
     21 /* -- Prototypes ---------------------------------------------------------- */
     22 
     23 void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
     24 {
     25   lj_mem_free(g, pt, pt->sizept);
     26 }
     27 
     28 /* -- Upvalues ------------------------------------------------------------ */
     29 
     30 static void unlinkuv(GCupval *uv)
     31 {
     32   lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
     33   setgcrefr(uvnext(uv)->prev, uv->prev);
     34   setgcrefr(uvprev(uv)->next, uv->next);
     35 }
     36 
     37 /* Find existing open upvalue for a stack slot or create a new one. */
     38 static GCupval *func_finduv(lua_State *L, TValue *slot)
     39 {
     40   global_State *g = G(L);
     41   GCRef *pp = &L->openupval;
     42   GCupval *p;
     43   GCupval *uv;
     44   /* Search the sorted list of open upvalues. */
     45   while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) {
     46     lua_assert(!p->closed && uvval(p) != &p->tv);
     47     if (uvval(p) == slot) {  /* Found open upvalue pointing to same slot? */
     48       if (isdead(g, obj2gco(p)))  /* Resurrect it, if it's dead. */
     49 	flipwhite(obj2gco(p));
     50       return p;
     51     }
     52     pp = &p->nextgc;
     53   }
     54   /* No matching upvalue found. Create a new one. */
     55   uv = lj_mem_newt(L, sizeof(GCupval), GCupval);
     56   newwhite(g, uv);
     57   uv->gct = ~LJ_TUPVAL;
     58   uv->closed = 0;  /* Still open. */
     59   setmref(uv->v, slot);  /* Pointing to the stack slot. */
     60   /* NOBARRIER: The GCupval is new (marked white) and open. */
     61   setgcrefr(uv->nextgc, *pp);  /* Insert into sorted list of open upvalues. */
     62   setgcref(*pp, obj2gco(uv));
     63   setgcref(uv->prev, obj2gco(&g->uvhead));  /* Insert into GC list, too. */
     64   setgcrefr(uv->next, g->uvhead.next);
     65   setgcref(uvnext(uv)->prev, obj2gco(uv));
     66   setgcref(g->uvhead.next, obj2gco(uv));
     67   lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
     68   return uv;
     69 }
     70 
     71 /* Create an empty and closed upvalue. */
     72 static GCupval *func_emptyuv(lua_State *L)
     73 {
     74   GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval));
     75   uv->gct = ~LJ_TUPVAL;
     76   uv->closed = 1;
     77   setnilV(&uv->tv);
     78   setmref(uv->v, &uv->tv);
     79   return uv;
     80 }
     81 
     82 /* Close all open upvalues pointing to some stack level or above. */
     83 void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
     84 {
     85   GCupval *uv;
     86   global_State *g = G(L);
     87   while (gcref(L->openupval) != NULL &&
     88 	 uvval((uv = gco2uv(gcref(L->openupval)))) >= level) {
     89     GCobj *o = obj2gco(uv);
     90     lua_assert(!isblack(o) && !uv->closed && uvval(uv) != &uv->tv);
     91     setgcrefr(L->openupval, uv->nextgc);  /* No longer in open list. */
     92     if (isdead(g, o)) {
     93       lj_func_freeuv(g, uv);
     94     } else {
     95       unlinkuv(uv);
     96       lj_gc_closeuv(g, uv);
     97     }
     98   }
     99 }
    100 
    101 void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv)
    102 {
    103   if (!uv->closed)
    104     unlinkuv(uv);
    105   lj_mem_freet(g, uv);
    106 }
    107 
    108 /* -- Functions (closures) ------------------------------------------------ */
    109 
    110 GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
    111 {
    112   GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeCfunc(nelems));
    113   fn->c.gct = ~LJ_TFUNC;
    114   fn->c.ffid = FF_C;
    115   fn->c.nupvalues = (uint8_t)nelems;
    116   /* NOBARRIER: The GCfunc is new (marked white). */
    117   setmref(fn->c.pc, &G(L)->bc_cfunc_ext);
    118   setgcref(fn->c.env, obj2gco(env));
    119   return fn;
    120 }
    121 
    122 static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env)
    123 {
    124   uint32_t count;
    125   GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
    126   /* Initially points to itself */
    127   setgcref(fn->l.prev_ENV, obj2gco(fn));
    128   setgcref(fn->l.next_ENV, obj2gco(fn));
    129   fn->l.gct = ~LJ_TFUNC;
    130   fn->l.ffid = FF_LUA;
    131   fn->l.nupvalues = 0;  /* Set to zero until upvalues are initialized. */
    132   /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
    133   setmref(fn->l.pc, proto_bc(pt));
    134   setgcref(fn->l.env, obj2gco(env));
    135   /* Saturating 3 bit counter (0..7) for created closures. */
    136   count = (uint32_t)pt->flags + PROTO_CLCOUNT;
    137   pt->flags = (uint8_t)(count - ((count >> PROTO_CLC_BITS) & PROTO_CLCOUNT));
    138   return fn;
    139 }
    140 
    141 static GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCfuncL *parent);
    142 /* Recursively instantiate closures */
    143 static inline
    144 void lj_func_init_closure(lua_State *L, uintptr_t i, GCproto *pttab, GCfuncL *parent, GCupval *uv)
    145 {
    146   setfuncV(L, &uv->tv, lj_func_newL(L, &proto_kgc(pttab, (~i))->pt, parent));
    147 }
    148 
    149 /* Create a new Lua function with empty upvalues. */
    150 GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
    151 {
    152   GCfunc *fn = func_newL(L, pt, env);
    153   MSize i, nuv = pt->sizeuv;
    154   for (i = 0; i < nuv; i++) {
    155     GCupval *uv = func_emptyuv(L);
    156     uint32_t v = proto_uv(pt)[i];
    157     uint8_t flags = (v >> PROTO_UV_SHIFT);
    158     if (flags == UV_HOLE) {
    159       setgcrefnull(fn->l.uvptr[i]);
    160       continue;
    161     }
    162     uv->flags = flags;
    163     uv->dhash = (uint32_t)(uintptr_t)pt ^ ((uint32_t)proto_uv(pt)[i] << 24);
    164     /* NOBARRIER: The GCfunc is new (marked white). */
    165     setgcref(fn->l.uvptr[i], obj2gco(uv));
    166     /* TBD: sub-closures and env barriers? */
    167     if (flags == UV_ENV) {
    168       settabV(L, &uv->tv, env);
    169     } else if (flags == UV_CLOSURE)
    170       lj_func_init_closure(L, v & PROTO_UV_MASK, pt, &fn->l, uv);
    171   }
    172   fn->l.nupvalues = (uint8_t)nuv;
    173   return fn;
    174 }
    175 
    176 /* Do a GC check and create a new Lua function with inherited upvalues. */
    177 static GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCfuncL *parent)
    178 {
    179   GCfunc *fn;
    180   GCRef *puv;
    181   MSize i, nuv;
    182   TValue *base;
    183 
    184   fn = func_newL(L, pt, tabref(parent->env));
    185   /* NOBARRIER: The GCfunc is new (marked white). */
    186   puv = parent->uvptr;
    187   nuv = pt->sizeuv;
    188   base = L->base;
    189 
    190   fn->l.nupvalues = 0;
    191   /* TBD: sub-closures and env barriers? */
    192   for (i = 0; i < nuv; i++) {
    193     uint32_t v = proto_uv(pt)[i];
    194     GCupval *uv;
    195     switch (v >> PROTO_UV_SHIFT) {
    196       case UV_CLOSURE:
    197         uv = func_emptyuv(L);
    198         uv->flags = v >> PROTO_UV_SHIFT;
    199         setgcref(fn->l.uvptr[i], obj2gco(uv));
    200         lj_func_init_closure(L, v & PROTO_UV_MASK, pt, &fn->l, uv);
    201         break;
    202       case UV_ENV:
    203         //lua_assert(0);
    204       case UV_CHAINED:
    205         uv = &gcref(puv[v & PROTO_UV_MASK])->uv;
    206         lua_assert(uv);
    207         if (uv->flags & UV_ENV) {
    208           setgcref(fn->l.next_ENV, obj2gco(parent));
    209           fn->l.prev_ENV = parent->prev_ENV;
    210           setgcref(gcref(fn->l.prev_ENV)->fn.l.next_ENV, obj2gco(fn));
    211           setgcref(parent->prev_ENV, obj2gco(fn));
    212         }
    213         setgcref(fn->l.uvptr[i], obj2gco(uv));
    214         break;
    215       case UV_IMMUTABLE:
    216       case UV_LOCAL:
    217         uv = func_finduv(L, base + (v & 0xff));
    218         uv->flags = v >> PROTO_UV_SHIFT;
    219         uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24);
    220         setgcref(fn->l.uvptr[i], obj2gco(uv));
    221         break;
    222       case UV_HOLE:
    223         setgcrefnull(fn->l.uvptr[i]);
    224         continue;
    225       default:
    226         lua_assert(0);
    227     }
    228   }
    229   fn->l.nupvalues = (uint8_t)nuv;
    230   return fn;
    231 }
    232   
    233 GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
    234 {
    235   lj_gc_check_fixtop(L);
    236   return lj_func_newL(L, pt, parent);
    237 }
    238 
    239 void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn)
    240 {
    241   MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) :
    242 			       sizeCfunc((MSize)fn->c.nupvalues);
    243   /* NOBARRIER: Should be handled in ESETV/lua_setupvalue. */
    244   if (isluafunc(fn)) {
    245     setgcrefr(gcref(fn->l.next_ENV)->fn.l.prev_ENV, fn->l.prev_ENV);
    246     setgcrefr(gcref(fn->l.prev_ENV)->fn.l.next_ENV, fn->l.next_ENV);
    247   }
    248   lj_mem_free(g, fn, size);
    249 }
    250