summaryrefslogtreecommitdiff
path: root/src/lj_func.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_func.c')
-rw-r--r--src/lj_func.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/lj_func.c b/src/lj_func.c
new file mode 100644
index 00000000..92cdeda2
--- /dev/null
+++ b/src/lj_func.c
@@ -0,0 +1,185 @@
1/*
2** Function handling (prototypes, functions and upvalues).
3** Copyright (C) 2005-2009 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
20GCproto *lj_func_newproto(lua_State *L)
21{
22 GCproto *pt = lj_mem_newobj(L, GCproto);
23 pt->gct = ~LJ_TPROTO;
24 pt->numparams = 0;
25 pt->framesize = 0;
26 pt->sizeuv = 0;
27 pt->flags = 0;
28 pt->trace = 0;
29 pt->k.n = NULL;
30 pt->bc = NULL;
31 pt->uv = NULL;
32 pt->sizebc = 0;
33 pt->sizekgc = 0;
34 pt->sizekn = 0;
35 pt->sizelineinfo = 0;
36 pt->sizevarinfo = 0;
37 pt->sizeuvname = 0;
38 pt->linedefined = 0;
39 pt->lastlinedefined = 0;
40 pt->lineinfo = NULL;
41 pt->varinfo = NULL;
42 pt->uvname = NULL;
43 pt->chunkname = NULL;
44 return pt;
45}
46
47void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
48{
49 MSize nkgc = round_nkgc(pt->sizekgc);
50 MSize sizek = nkgc*(MSize)sizeof(GCobj *) +
51 pt->sizekn*(MSize)sizeof(lua_Number);
52 lj_mem_free(g, pt->k.gc - nkgc, sizek);
53 lj_mem_freevec(g, pt->bc, pt->sizebc, BCIns);
54 lj_mem_freevec(g, pt->uv, pt->sizeuv, int16_t);
55 lj_mem_freevec(g, pt->lineinfo, pt->sizelineinfo, int32_t);
56 lj_mem_freevec(g, pt->varinfo, pt->sizevarinfo, struct VarInfo);
57 lj_mem_freevec(g, pt->uvname, pt->sizeuvname, GCstr *);
58 lj_trace_freeproto(g, pt);
59 lj_mem_freet(g, pt);
60}
61
62/* -- Upvalues ------------------------------------------------------------ */
63
64static void unlinkuv(GCupval *uv)
65{
66 lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
67 setgcrefr(uvnext(uv)->prev, uv->prev);
68 setgcrefr(uvprev(uv)->next, uv->next);
69}
70
71/* Find existing open upvalue for a stack slot or create a new one. */
72static GCupval *func_finduv(lua_State *L, TValue *slot)
73{
74 global_State *g = G(L);
75 GCRef *pp = &L->openupval;
76 GCupval *p;
77 GCupval *uv;
78 /* Search the sorted list of open upvalues. */
79 while (gcref(*pp) != NULL && (p = gco2uv(gcref(*pp)))->v >= slot) {
80 lua_assert(!p->closed && p->v != &p->tv);
81 if (p->v == slot) { /* Found open upvalue pointing to same slot? */
82 if (isdead(g, obj2gco(p))) /* Resurrect it, if it's dead. */
83 flipwhite(obj2gco(p));
84 return p;
85 }
86 pp = &p->nextgc;
87 }
88 /* No matching upvalue found. Create a new one. */
89 uv = lj_mem_newt(L, sizeof(GCupval), GCupval);
90 newwhite(g, uv);
91 uv->gct = ~LJ_TUPVAL;
92 uv->closed = 0; /* Still open. */
93 uv->v = slot; /* Pointing to the stack slot. */
94 /* NOBARRIER: The GCupval is new (marked white) and open. */
95 setgcrefr(uv->nextgc, *pp); /* Insert into sorted list of open upvalues. */
96 setgcref(*pp, obj2gco(uv));
97 setgcref(uv->prev, obj2gco(&g->uvhead)); /* Insert into GC list, too. */
98 setgcrefr(uv->next, g->uvhead.next);
99 setgcref(uvnext(uv)->prev, obj2gco(uv));
100 setgcref(g->uvhead.next, obj2gco(uv));
101 lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
102 return uv;
103}
104
105/* Close all open upvalues pointing to some stack level or above. */
106void lj_func_closeuv(lua_State *L, TValue *level)
107{
108 GCupval *uv;
109 global_State *g = G(L);
110 while (gcref(L->openupval) != NULL &&
111 (uv = gco2uv(gcref(L->openupval)))->v >= level) {
112 GCobj *o = obj2gco(uv);
113 lua_assert(!isblack(o) && !uv->closed && uv->v != &uv->tv);
114 setgcrefr(L->openupval, uv->nextgc); /* No longer in open list. */
115 if (isdead(g, o)) {
116 lj_func_freeuv(g, uv);
117 } else {
118 unlinkuv(uv);
119 lj_gc_closeuv(g, uv);
120 }
121 }
122}
123
124void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv)
125{
126 if (!uv->closed)
127 unlinkuv(uv);
128 lj_mem_freet(g, uv);
129}
130
131/* -- Functions (closures) ------------------------------------------------ */
132
133GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
134{
135 GCfunc *fn = cast(GCfunc *, lj_mem_newgco(L, sizeCfunc(nelems)));
136 fn->c.gct = ~LJ_TFUNC;
137 fn->c.ffid = FF_C;
138 fn->c.nupvalues = cast_byte(nelems);
139 /* NOBARRIER: The GCfunc is new (marked white). */
140 setgcref(fn->c.env, obj2gco(env));
141 fn->c.gate = lj_gate_c;
142 return fn;
143}
144
145GCfunc *lj_func_newL(lua_State *L, GCproto *pt, GCtab *env)
146{
147 GCfunc *fn = cast(GCfunc *, lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv)));
148 fn->l.gct = ~LJ_TFUNC;
149 fn->l.ffid = FF_LUA;
150 fn->l.nupvalues = cast_byte(pt->sizeuv);
151 /* NOBARRIER: The GCfunc is new (marked white). */
152 setgcref(fn->l.pt, obj2gco(pt));
153 setgcref(fn->l.env, obj2gco(env));
154 fn->l.gate = (pt->flags & PROTO_IS_VARARG) ? lj_gate_lv : lj_gate_lf;
155 return fn;
156}
157
158/* Do a GC check and create a new Lua function with inherited upvalues. */
159GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
160{
161 GCfunc *fn;
162 GCRef *puv;
163 uint32_t i, nuv;
164 TValue *base;
165 lj_gc_check_fixtop(L);
166 fn = lj_func_newL(L, pt, tabref(parent->env));
167 /* NOBARRIER: The GCfunc is new (marked white). */
168 puv = parent->uvptr;
169 nuv = fn->l.nupvalues;
170 base = L->base;
171 for (i = 0; i < nuv; i++) {
172 int v = pt->uv[i];
173 GCupval *uv = v < 0 ? &gcref(puv[~v])->uv : func_finduv(L, base + v);
174 setgcref(fn->l.uvptr[i], obj2gco(uv));
175 }
176 return fn;
177}
178
179void 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