Cleanup various endianess issues in assembler backend.
[luajit-2.0.git] / src / lj_func.c
blob334ba4c8509a49d88448634d6b229e51ec9396df
1 /*
2 ** Function handling (prototypes, functions and upvalues).
3 ** Copyright (C) 2005-2011 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 */
9 #define lj_func_c
10 #define LUA_CORE
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"
18 /* -- Prototypes ---------------------------------------------------------- */
20 void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
22 lj_mem_free(g, pt, pt->sizept);
25 /* -- Upvalues ------------------------------------------------------------ */
27 static void unlinkuv(GCupval *uv)
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);
34 /* Find existing open upvalue for a stack slot or create a new one. */
35 static GCupval *func_finduv(lua_State *L, TValue *slot)
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;
49 pp = &p->nextgc;
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;
68 /* Create an empty and closed upvalue. */
69 static GCupval *func_emptyuv(lua_State *L)
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;
79 /* Close all open upvalues pointing to some stack level or above. */
80 void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
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);
98 void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv)
100 if (!uv->closed)
101 unlinkuv(uv);
102 lj_mem_freet(g, uv);
105 /* -- Functions (closures) ------------------------------------------------ */
107 GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
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;
119 static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env)
121 GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
122 fn->l.gct = ~LJ_TFUNC;
123 fn->l.ffid = FF_LUA;
124 fn->l.nupvalues = 0; /* Set to zero until upvalues are initialized. */
125 /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
126 setmref(fn->l.pc, proto_bc(pt));
127 setgcref(fn->l.env, obj2gco(env));
128 return fn;
131 /* Create a new Lua function with empty upvalues. */
132 GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
134 GCfunc *fn = func_newL(L, pt, env);
135 MSize i, nuv = pt->sizeuv;
136 /* NOBARRIER: The GCfunc is new (marked white). */
137 for (i = 0; i < nuv; i++) {
138 GCupval *uv = func_emptyuv(L);
139 uv->dhash = (uint32_t)(uintptr_t)pt ^ ((uint32_t)proto_uv(pt)[i] << 24);
140 setgcref(fn->l.uvptr[i], obj2gco(uv));
142 fn->l.nupvalues = (uint8_t)nuv;
143 return fn;
146 /* Do a GC check and create a new Lua function with inherited upvalues. */
147 GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
149 GCfunc *fn;
150 GCRef *puv;
151 MSize i, nuv;
152 TValue *base;
153 lj_gc_check_fixtop(L);
154 fn = func_newL(L, pt, tabref(parent->env));
155 /* NOBARRIER: The GCfunc is new (marked white). */
156 puv = parent->uvptr;
157 nuv = pt->sizeuv;
158 base = L->base;
159 for (i = 0; i < nuv; i++) {
160 uint32_t v = proto_uv(pt)[i];
161 GCupval *uv;
162 if ((v & 0x8000)) {
163 uv = func_finduv(L, base + (v & 0xff));
164 uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24);
165 } else {
166 uv = &gcref(puv[v])->uv;
168 setgcref(fn->l.uvptr[i], obj2gco(uv));
170 fn->l.nupvalues = (uint8_t)nuv;
171 return fn;
174 void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn)
176 MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) :
177 sizeCfunc((MSize)fn->c.nupvalues);
178 lj_mem_free(g, fn, size);