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
20void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
21{
22 lj_mem_free(g, pt, pt->sizept);
23}
24
25/* -- Upvalues ------------------------------------------------------------ */
26
27static 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. */
37static 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. */
72static 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. */
83void 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
102void 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
111GCfunc *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
123static 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. */
140GCfunc *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. */
157GCfunc *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
185void 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