| 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 | |