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