| 1 | /* | 
|---|
| 2 | ** Function handling (prototypes, functions and upvalues). | 
|---|
| 3 | ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h | 
|---|
| 4 | ** | 
|---|
| 5 | ** Portions taken verbatim or adapted from the Lua interpreter. | 
|---|
| 6 | ** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h | 
|---|
| 7 | */ | 
|---|
| 8 |  | 
|---|
| 9 | #define lj_func_c | 
|---|
| 10 | #define LUA_CORE | 
|---|
| 11 |  | 
|---|
| 12 | #include "lj_obj.h" | 
|---|
| 13 | #include "lj_gc.h" | 
|---|
| 14 | #include "lj_func.h" | 
|---|
| 15 | #include "lj_trace.h" | 
|---|
| 16 | #include "lj_vm.h" | 
|---|
| 17 |  | 
|---|
| 18 | /* -- Prototypes ---------------------------------------------------------- */ | 
|---|
| 19 |  | 
|---|
| 20 | void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt) | 
|---|
| 21 | { | 
|---|
| 22 | lj_mem_free(g, pt, pt->sizept); | 
|---|
| 23 | } | 
|---|
| 24 |  | 
|---|
| 25 | /* -- Upvalues ------------------------------------------------------------ */ | 
|---|
| 26 |  | 
|---|
| 27 | static void unlinkuv(global_State *g, GCupval *uv) | 
|---|
| 28 | { | 
|---|
| 29 | UNUSED(g); | 
|---|
| 30 | lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv, | 
|---|
| 31 | "broken upvalue chain"); | 
|---|
| 32 | setgcrefr(uvnext(uv)->prev, uv->prev); | 
|---|
| 33 | setgcrefr(uvprev(uv)->next, uv->next); | 
|---|
| 34 | } | 
|---|
| 35 |  | 
|---|
| 36 | /* Find existing open upvalue for a stack slot or create a new one. */ | 
|---|
| 37 | static GCupval *func_finduv(lua_State *L, TValue *slot) | 
|---|
| 38 | { | 
|---|
| 39 | global_State *g = G(L); | 
|---|
| 40 | GCRef *pp = &L->openupval; | 
|---|
| 41 | GCupval *p; | 
|---|
| 42 | GCupval *uv; | 
|---|
| 43 | /* Search the sorted list of open upvalues. */ | 
|---|
| 44 | while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) { | 
|---|
| 45 | lj_assertG(!p->closed && uvval(p) != &p->tv, "closed upvalue in chain"); | 
|---|
| 46 | if (uvval(p) == slot) {  /* Found open upvalue pointing to same slot? */ | 
|---|
| 47 | if (isdead(g, obj2gco(p)))  /* Resurrect it, if it's dead. */ | 
|---|
| 48 | flipwhite(obj2gco(p)); | 
|---|
| 49 | return p; | 
|---|
| 50 | } | 
|---|
| 51 | pp = &p->nextgc; | 
|---|
| 52 | } | 
|---|
| 53 | /* No matching upvalue found. Create a new one. */ | 
|---|
| 54 | uv = lj_mem_newt(L, sizeof(GCupval), GCupval); | 
|---|
| 55 | newwhite(g, uv); | 
|---|
| 56 | uv->gct = ~LJ_TUPVAL; | 
|---|
| 57 | uv->closed = 0;  /* Still open. */ | 
|---|
| 58 | setmref(uv->v, slot);  /* Pointing to the stack slot. */ | 
|---|
| 59 | /* NOBARRIER: The GCupval is new (marked white) and open. */ | 
|---|
| 60 | setgcrefr(uv->nextgc, *pp);  /* Insert into sorted list of open upvalues. */ | 
|---|
| 61 | setgcref(*pp, obj2gco(uv)); | 
|---|
| 62 | setgcref(uv->prev, obj2gco(&g->uvhead));  /* Insert into GC list, too. */ | 
|---|
| 63 | setgcrefr(uv->next, g->uvhead.next); | 
|---|
| 64 | setgcref(uvnext(uv)->prev, obj2gco(uv)); | 
|---|
| 65 | setgcref(g->uvhead.next, obj2gco(uv)); | 
|---|
| 66 | lj_assertG(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv, | 
|---|
| 67 | "broken upvalue chain"); | 
|---|
| 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 | lj_assertG(!isblack(o), "bad black upvalue"); | 
|---|
| 91 | lj_assertG(!uv->closed && uvval(uv) != &uv->tv, "closed upvalue in chain"); | 
|---|
| 92 | setgcrefr(L->openupval, uv->nextgc);  /* No longer in open list. */ | 
|---|
| 93 | if (isdead(g, o)) { | 
|---|
| 94 | lj_func_freeuv(g, uv); | 
|---|
| 95 | } else { | 
|---|
| 96 | unlinkuv(g, uv); | 
|---|
| 97 | lj_gc_closeuv(g, uv); | 
|---|
| 98 | } | 
|---|
| 99 | } | 
|---|
| 100 | } | 
|---|
| 101 |  | 
|---|
| 102 | void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv) | 
|---|
| 103 | { | 
|---|
| 104 | if (!uv->closed) | 
|---|
| 105 | unlinkuv(g, uv); | 
|---|
| 106 | lj_mem_freet(g, uv); | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | /* -- Functions (closures) ------------------------------------------------ */ | 
|---|
| 110 |  | 
|---|
| 111 | GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env) | 
|---|
| 112 | { | 
|---|
| 113 | GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeCfunc(nelems)); | 
|---|
| 114 | fn->c.gct = ~LJ_TFUNC; | 
|---|
| 115 | fn->c.ffid = FF_C; | 
|---|
| 116 | fn->c.nupvalues = (uint8_t)nelems; | 
|---|
| 117 | /* NOBARRIER: The GCfunc is new (marked white). */ | 
|---|
| 118 | setmref(fn->c.pc, &G(L)->bc_cfunc_ext); | 
|---|
| 119 | setgcref(fn->c.env, obj2gco(env)); | 
|---|
| 120 | return fn; | 
|---|
| 121 | } | 
|---|
| 122 |  | 
|---|
| 123 | static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env) | 
|---|
| 124 | { | 
|---|
| 125 | uint32_t count; | 
|---|
| 126 | GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv)); | 
|---|
| 127 | fn->l.gct = ~LJ_TFUNC; | 
|---|
| 128 | fn->l.ffid = FF_LUA; | 
|---|
| 129 | fn->l.nupvalues = 0;  /* Set to zero until upvalues are initialized. */ | 
|---|
| 130 | /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */ | 
|---|
| 131 | setmref(fn->l.pc, proto_bc(pt)); | 
|---|
| 132 | setgcref(fn->l.env, obj2gco(env)); | 
|---|
| 133 | /* Saturating 3 bit counter (0..7) for created closures. */ | 
|---|
| 134 | count = (uint32_t)pt->flags + PROTO_CLCOUNT; | 
|---|
| 135 | pt->flags = (uint8_t)(count - ((count >> PROTO_CLC_BITS) & PROTO_CLCOUNT)); | 
|---|
| 136 | return fn; | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | /* Create a new Lua function with empty upvalues. */ | 
|---|
| 140 | GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env) | 
|---|
| 141 | { | 
|---|
| 142 | GCfunc *fn = func_newL(L, pt, env); | 
|---|
| 143 | MSize i, nuv = pt->sizeuv; | 
|---|
| 144 | /* NOBARRIER: The GCfunc is new (marked white). */ | 
|---|
| 145 | for (i = 0; i < nuv; i++) { | 
|---|
| 146 | GCupval *uv = func_emptyuv(L); | 
|---|
| 147 | int32_t v = proto_uv(pt)[i]; | 
|---|
| 148 | uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1); | 
|---|
| 149 | uv->dhash = (uint32_t)(uintptr_t)pt ^ (v << 24); | 
|---|
| 150 | setgcref(fn->l.uvptr[i], obj2gco(uv)); | 
|---|
| 151 | } | 
|---|
| 152 | fn->l.nupvalues = (uint8_t)nuv; | 
|---|
| 153 | return fn; | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | /* Do a GC check and create a new Lua function with inherited upvalues. */ | 
|---|
| 157 | GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent) | 
|---|
| 158 | { | 
|---|
| 159 | GCfunc *fn; | 
|---|
| 160 | GCRef *puv; | 
|---|
| 161 | MSize i, nuv; | 
|---|
| 162 | TValue *base; | 
|---|
| 163 | lj_gc_check_fixtop(L); | 
|---|
| 164 | fn = func_newL(L, pt, tabref(parent->env)); | 
|---|
| 165 | /* NOBARRIER: The GCfunc is new (marked white). */ | 
|---|
| 166 | puv = parent->uvptr; | 
|---|
| 167 | nuv = pt->sizeuv; | 
|---|
| 168 | base = L->base; | 
|---|
| 169 | for (i = 0; i < nuv; i++) { | 
|---|
| 170 | uint32_t v = proto_uv(pt)[i]; | 
|---|
| 171 | GCupval *uv; | 
|---|
| 172 | if ((v & PROTO_UV_LOCAL)) { | 
|---|
| 173 | uv = func_finduv(L, base + (v & 0xff)); | 
|---|
| 174 | uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1); | 
|---|
| 175 | uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24); | 
|---|
| 176 | } else { | 
|---|
| 177 | uv = &gcref(puv[v])->uv; | 
|---|
| 178 | } | 
|---|
| 179 | setgcref(fn->l.uvptr[i], obj2gco(uv)); | 
|---|
| 180 | } | 
|---|
| 181 | fn->l.nupvalues = (uint8_t)nuv; | 
|---|
| 182 | return fn; | 
|---|
| 183 | } | 
|---|
| 184 |  | 
|---|
| 185 | void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn) | 
|---|
| 186 | { | 
|---|
| 187 | MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) : | 
|---|
| 188 | sizeCfunc((MSize)fn->c.nupvalues); | 
|---|
| 189 | lj_mem_free(g, fn, size); | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 |  | 
|---|