| 1 | /* |
| 2 | ** Function handling (prototypes, functions and upvalues). |
| 3 | ** Copyright (C) 2005-2014 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(GCupval *uv) |
| 28 | { |
| 29 | lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); |
| 30 | setgcrefr(uvnext(uv)->prev, uv->prev); |
| 31 | setgcrefr(uvprev(uv)->next, uv->next); |
| 32 | } |
| 33 | |
| 34 | /* Find existing open upvalue for a stack slot or create a new one. */ |
| 35 | static GCupval *func_finduv(lua_State *L, TValue *slot) |
| 36 | { |
| 37 | global_State *g = G(L); |
| 38 | GCRef *pp = &L->openupval; |
| 39 | GCupval *p; |
| 40 | GCupval *uv; |
| 41 | /* Search the sorted list of open upvalues. */ |
| 42 | while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) { |
| 43 | lua_assert(!p->closed && uvval(p) != &p->tv); |
| 44 | if (uvval(p) == slot) { /* Found open upvalue pointing to same slot? */ |
| 45 | if (isdead(g, obj2gco(p))) /* Resurrect it, if it's dead. */ |
| 46 | flipwhite(obj2gco(p)); |
| 47 | return p; |
| 48 | } |
| 49 | pp = &p->nextgc; |
| 50 | } |
| 51 | /* No matching upvalue found. Create a new one. */ |
| 52 | uv = lj_mem_newt(L, sizeof(GCupval), GCupval); |
| 53 | newwhite(g, uv); |
| 54 | uv->gct = ~LJ_TUPVAL; |
| 55 | uv->closed = 0; /* Still open. */ |
| 56 | setmref(uv->v, slot); /* Pointing to the stack slot. */ |
| 57 | /* NOBARRIER: The GCupval is new (marked white) and open. */ |
| 58 | setgcrefr(uv->nextgc, *pp); /* Insert into sorted list of open upvalues. */ |
| 59 | setgcref(*pp, obj2gco(uv)); |
| 60 | setgcref(uv->prev, obj2gco(&g->uvhead)); /* Insert into GC list, too. */ |
| 61 | setgcrefr(uv->next, g->uvhead.next); |
| 62 | setgcref(uvnext(uv)->prev, obj2gco(uv)); |
| 63 | setgcref(g->uvhead.next, obj2gco(uv)); |
| 64 | lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv); |
| 65 | return uv; |
| 66 | } |
| 67 | |
| 68 | /* Create an empty and closed upvalue. */ |
| 69 | static GCupval *func_emptyuv(lua_State *L) |
| 70 | { |
| 71 | GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval)); |
| 72 | uv->gct = ~LJ_TUPVAL; |
| 73 | uv->closed = 1; |
| 74 | setnilV(&uv->tv); |
| 75 | setmref(uv->v, &uv->tv); |
| 76 | return uv; |
| 77 | } |
| 78 | |
| 79 | /* Close all open upvalues pointing to some stack level or above. */ |
| 80 | void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level) |
| 81 | { |
| 82 | GCupval *uv; |
| 83 | global_State *g = G(L); |
| 84 | while (gcref(L->openupval) != NULL && |
| 85 | uvval((uv = gco2uv(gcref(L->openupval)))) >= level) { |
| 86 | GCobj *o = obj2gco(uv); |
| 87 | lua_assert(!isblack(o) && !uv->closed && uvval(uv) != &uv->tv); |
| 88 | setgcrefr(L->openupval, uv->nextgc); /* No longer in open list. */ |
| 89 | if (isdead(g, o)) { |
| 90 | lj_func_freeuv(g, uv); |
| 91 | } else { |
| 92 | unlinkuv(uv); |
| 93 | lj_gc_closeuv(g, uv); |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv) |
| 99 | { |
| 100 | if (!uv->closed) |
| 101 | unlinkuv(uv); |
| 102 | lj_mem_freet(g, uv); |
| 103 | } |
| 104 | |
| 105 | /* -- Functions (closures) ------------------------------------------------ */ |
| 106 | |
| 107 | GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env) |
| 108 | { |
| 109 | GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeCfunc(nelems)); |
| 110 | fn->c.gct = ~LJ_TFUNC; |
| 111 | fn->c.ffid = FF_C; |
| 112 | fn->c.nupvalues = (uint8_t)nelems; |
| 113 | /* NOBARRIER: The GCfunc is new (marked white). */ |
| 114 | setmref(fn->c.pc, &G(L)->bc_cfunc_ext); |
| 115 | setgcref(fn->c.env, obj2gco(env)); |
| 116 | return fn; |
| 117 | } |
| 118 | |
| 119 | static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env) |
| 120 | { |
| 121 | uint32_t count; |
| 122 | GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv)); |
| 123 | fn->l.gct = ~LJ_TFUNC; |
| 124 | fn->l.ffid = FF_LUA; |
| 125 | fn->l.nupvalues = 0; /* Set to zero until upvalues are initialized. */ |
| 126 | /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */ |
| 127 | setmref(fn->l.pc, proto_bc(pt)); |
| 128 | setgcref(fn->l.env, obj2gco(env)); |
| 129 | /* Saturating 3 bit counter (0..7) for created closures. */ |
| 130 | count = (uint32_t)pt->flags + PROTO_CLCOUNT; |
| 131 | pt->flags = (uint8_t)(count - ((count >> PROTO_CLC_BITS) & PROTO_CLCOUNT)); |
| 132 | return fn; |
| 133 | } |
| 134 | |
| 135 | /* Create a new Lua function with empty upvalues. */ |
| 136 | GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env) |
| 137 | { |
| 138 | GCfunc *fn = func_newL(L, pt, env); |
| 139 | MSize i, nuv = pt->sizeuv; |
| 140 | /* NOBARRIER: The GCfunc is new (marked white). */ |
| 141 | for (i = 0; i < nuv; i++) { |
| 142 | GCupval *uv = func_emptyuv(L); |
| 143 | uv->dhash = (uint32_t)(uintptr_t)pt ^ ((uint32_t)proto_uv(pt)[i] << 24); |
| 144 | setgcref(fn->l.uvptr[i], obj2gco(uv)); |
| 145 | } |
| 146 | fn->l.nupvalues = (uint8_t)nuv; |
| 147 | return fn; |
| 148 | } |
| 149 | |
| 150 | /* Do a GC check and create a new Lua function with inherited upvalues. */ |
| 151 | GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent) |
| 152 | { |
| 153 | GCfunc *fn; |
| 154 | GCRef *puv; |
| 155 | MSize i, nuv; |
| 156 | TValue *base; |
| 157 | lj_gc_check_fixtop(L); |
| 158 | fn = func_newL(L, pt, tabref(parent->env)); |
| 159 | /* NOBARRIER: The GCfunc is new (marked white). */ |
| 160 | puv = parent->uvptr; |
| 161 | nuv = pt->sizeuv; |
| 162 | base = L->base; |
| 163 | for (i = 0; i < nuv; i++) { |
| 164 | uint32_t v = proto_uv(pt)[i]; |
| 165 | GCupval *uv; |
| 166 | if ((v & PROTO_UV_LOCAL)) { |
| 167 | uv = func_finduv(L, base + (v & 0xff)); |
| 168 | uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1); |
| 169 | uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24); |
| 170 | } else { |
| 171 | uv = &gcref(puv[v])->uv; |
| 172 | } |
| 173 | setgcref(fn->l.uvptr[i], obj2gco(uv)); |
| 174 | } |
| 175 | fn->l.nupvalues = (uint8_t)nuv; |
| 176 | return fn; |
| 177 | } |
| 178 | |
| 179 | void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn) |
| 180 | { |
| 181 | MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) : |
| 182 | sizeCfunc((MSize)fn->c.nupvalues); |
| 183 | lj_mem_free(g, fn, size); |
| 184 | } |
| 185 | |
| 186 | |