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