summaryrefslogtreecommitdiff
path: root/src/lj_meta.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_meta.c')
-rw-r--r--src/lj_meta.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/src/lj_meta.c b/src/lj_meta.c
new file mode 100644
index 00000000..dff01f85
--- /dev/null
+++ b/src/lj_meta.c
@@ -0,0 +1,358 @@
1/*
2** Metamethod handling.
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_meta_c
10#define LUA_CORE
11
12#include "lj_obj.h"
13#include "lj_gc.h"
14#include "lj_err.h"
15#include "lj_str.h"
16#include "lj_tab.h"
17#include "lj_meta.h"
18#include "lj_bc.h"
19#include "lj_vm.h"
20
21/* -- Metamethod handling ------------------------------------------------- */
22
23/* String interning of metamethod names for fast indexing. */
24void lj_meta_init(lua_State *L)
25{
26#define MMNAME(name) "__" #name
27 const char *metanames = MMDEF(MMNAME);
28#undef MMNAME
29 global_State *g = G(L);
30 const char *p, *q;
31 uint32_t i;
32 for (i = 0, p = metanames; *p; i++, p = q) {
33 GCstr *s;
34 for (q = p+2; *q && *q != '_'; q++) ;
35 s = lj_str_new(L, p, (size_t)(q-p));
36 fixstring(s); /* Never collect these names. */
37 /* NOBARRIER: g->mmname[] is a GC root. */
38 setgcref(g->mmname[i], obj2gco(s));
39 }
40}
41
42/* Negative caching of a few fast metamethods. See the lj_meta_fast() macro. */
43cTValue *lj_meta_cache(GCtab *mt, MMS mm, GCstr *name)
44{
45 cTValue *mo = lj_tab_getstr(mt, name);
46 lua_assert(mm <= MM_FAST);
47 if (!mo || tvisnil(mo)) { /* No metamethod? */
48 mt->nomm |= cast_byte(1u<<mm); /* Set negative cache flag. */
49 return NULL;
50 }
51 return mo;
52}
53
54/* Lookup metamethod for object. */
55cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm)
56{
57 GCtab *mt;
58 if (tvistab(o))
59 mt = tabref(tabV(o)->metatable);
60 else if (tvisudata(o))
61 mt = tabref(udataV(o)->metatable);
62 else
63 mt = tabref(G(L)->basemt[itypemap(o)]);
64 if (mt) {
65 cTValue *mo = lj_tab_getstr(mt, strref(G(L)->mmname[mm]));
66 if (mo)
67 return mo;
68 }
69 return niltv(L);
70}
71
72/* Setup call to metamethod to be run by Assembler VM. */
73static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo,
74 cTValue *a, cTValue *b)
75{
76 /*
77 ** |-- framesize -> top top+1 top+2 top+3
78 ** before: [func slots ...]
79 ** mm setup: [func slots ...] [cont|?] [mo|tmtype] [a] [b]
80 ** in asm: [func slots ...] [cont|PC] [mo|delta] [a] [b]
81 ** ^-- func base ^-- mm base
82 ** after mm: [func slots ...] [result]
83 ** ^-- copy to base[PC_RA] --/ for lj_cont_ra
84 ** istruecond + branch for lj_cont_cond*
85 ** ignore for lj_cont_nop
86 ** next PC: [func slots ...]
87 */
88 TValue *top = L->top;
89 if (curr_funcisL(L)) top = curr_topL(L);
90 setcont(top, cont); /* Assembler VM stores PC in upper word. */
91 copyTV(L, top+1, mo); /* Store metamethod and two arguments. */
92 copyTV(L, top+2, a);
93 copyTV(L, top+3, b);
94 return top+2; /* Return new base. */
95}
96
97/* -- C helpers for some instructions, called from assembler VM ----------- */
98
99/* Helper for TGET*. __index chain and metamethod. */
100cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k)
101{
102 int loop;
103 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) {
104 cTValue *mo;
105 if (tvistab(o)) {
106 GCtab *t = tabV(o);
107 cTValue *tv = lj_tab_get(L, t, k);
108 if (!tvisnil(tv) ||
109 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_index)))
110 return tv;
111 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_index))) {
112 lj_err_optype(L, o, LJ_ERR_OPINDEX);
113 return NULL; /* unreachable */
114 }
115 if (tvisfunc(mo)) {
116 L->top = mmcall(L, lj_cont_ra, mo, o, k);
117 return NULL; /* Trigger metamethod call. */
118 }
119 o = mo;
120 }
121 lj_err_msg(L, LJ_ERR_GETLOOP);
122 return NULL; /* unreachable */
123}
124
125/* Helper for TSET*. __newindex chain and metamethod. */
126TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k)
127{
128 TValue tmp;
129 int loop;
130 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) {
131 cTValue *mo;
132 if (tvistab(o)) {
133 GCtab *t = tabV(o);
134 TValue *tv = lj_tab_set(L, t, k);
135 if (!tvisnil(tv) ||
136 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) {
137 if (isblack(obj2gco(t))) lj_gc_barrierback(G(L), t);
138 return tv;
139 }
140 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) {
141 lj_err_optype(L, o, LJ_ERR_OPINDEX);
142 return NULL; /* unreachable */
143 }
144 if (tvisfunc(mo)) {
145 L->top = mmcall(L, lj_cont_nop, mo, o, k);
146 /* L->top+2 = v filled in by caller. */
147 return NULL; /* Trigger metamethod call. */
148 }
149 copyTV(L, &tmp, mo);
150 o = &tmp;
151 }
152 lj_err_msg(L, LJ_ERR_SETLOOP);
153 return NULL; /* unreachable */
154}
155
156static cTValue *str2num(cTValue *o, TValue *n)
157{
158 if (tvisnum(o))
159 return o;
160 else if (tvisstr(o) && lj_str_numconv(strVdata(o), n))
161 return n;
162 else
163 return NULL;
164}
165
166/* Helper for arithmetic instructions. Coercion, metamethod. */
167TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc,
168 BCReg op)
169{
170 MMS mm = bcmode_mm(op);
171 TValue tempb, tempc;
172 cTValue *b, *c;
173 if ((b = str2num(rb, &tempb)) != NULL &&
174 (c = str2num(rc, &tempc)) != NULL) { /* Try coercion first. */
175 setnumV(ra, lj_vm_foldarith(numV(b), numV(c), (int)mm-MM_add));
176 return NULL;
177 } else {
178 cTValue *mo = lj_meta_lookup(L, rb, mm);
179 if (tvisnil(mo)) {
180 mo = lj_meta_lookup(L, rc, mm);
181 if (tvisnil(mo)) {
182 if (str2num(rb, &tempb) == NULL) rc = rb;
183 lj_err_optype(L, rc, LJ_ERR_OPARITH);
184 return NULL; /* unreachable */
185 }
186 }
187 return mmcall(L, lj_cont_ra, mo, rb, rc);
188 }
189}
190
191/* In-place coercion of a number to a string. */
192static LJ_AINLINE int tostring(lua_State *L, TValue *o)
193{
194 if (tvisstr(o)) {
195 return 1;
196 } else if (tvisnum(o)) {
197 setstrV(L, o, lj_str_fromnum(L, &o->n));
198 return 1;
199 } else {
200 return 0;
201 }
202}
203
204/* Helper for CAT. Coercion, iterative concat, __concat metamethod. */
205TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
206{
207 do {
208 int n = 1;
209 if (!(tvisstr(top-1) || tvisnum(top-1)) || !tostring(L, top)) {
210 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat);
211 if (tvisnil(mo)) {
212 mo = lj_meta_lookup(L, top, MM_concat);
213 if (tvisnil(mo)) {
214 if (tvisstr(top-1) || tvisnum(top-1)) top++;
215 lj_err_optype(L, top-1, LJ_ERR_OPCAT);
216 return NULL; /* unreachable */
217 }
218 }
219 /* One of the top two elements is not a string, call __cat metamethod:
220 **
221 ** before: [...][CAT stack .........................]
222 ** top-1 top top+1 top+2
223 ** pick two: [...][CAT stack ...] [o1] [o2]
224 ** setup mm: [...][CAT stack ...] [cont|?] [mo|tmtype] [o1] [o2]
225 ** in asm: [...][CAT stack ...] [cont|PC] [mo|delta] [o1] [o2]
226 ** ^-- func base ^-- mm base
227 ** after mm: [...][CAT stack ...] <--push-- [result]
228 ** next step: [...][CAT stack .............]
229 */
230 copyTV(L, top+2, top) /* Careful with the order of stack copies! */
231 copyTV(L, top+1, top-1)
232 copyTV(L, top, mo)
233 setcont(top-1, lj_cont_cat);
234 return top+1; /* Trigger metamethod call. */
235 } else if (strV(top)->len == 0) { /* Shortcut. */
236 (void)tostring(L, top-1);
237 } else {
238 /* Pick as many strings as possible from the top and concatenate them:
239 **
240 ** before: [...][CAT stack ...........................]
241 ** pick str: [...][CAT stack ...] [...... strings ......]
242 ** concat: [...][CAT stack ...] [result]
243 ** next step: [...][CAT stack ............]
244 */
245 MSize tlen = strV(top)->len;
246 char *buffer;
247 int i;
248 for (n = 1; n <= left && tostring(L, top-n); n++) {
249 MSize len = strV(top-n)->len;
250 if (len >= LJ_MAX_STR - tlen)
251 lj_err_msg(L, LJ_ERR_STROV);
252 tlen += len;
253 }
254 buffer = lj_str_needbuf(L, &G(L)->tmpbuf, tlen);
255 n--;
256 tlen = 0;
257 for (i = n; i >= 0; i--) {
258 MSize len = strV(top-i)->len;
259 memcpy(buffer + tlen, strVdata(top-i), len);
260 tlen += len;
261 }
262 setstrV(L, top-n, lj_str_new(L, buffer, tlen));
263 }
264 left -= n;
265 top -= n;
266 } while (left >= 1);
267 lj_gc_check_fixtop(L);
268 return NULL;
269}
270
271/* Helper for LEN. __len metamethod. */
272TValue *lj_meta_len(lua_State *L, cTValue *o)
273{
274 cTValue *mo = lj_meta_lookup(L, o, MM_len);
275 if (tvisnil(mo)) {
276 lj_err_optype(L, o, LJ_ERR_OPLEN);
277 return NULL; /* unreachable */
278 }
279 return mmcall(L, lj_cont_ra, mo, o, niltv(L));
280}
281
282/* Helper for equality comparisons. __eq metamethod. */
283TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne)
284{
285 /* Field metatable must be at same offset for GCtab and GCudata! */
286 cTValue *mo = lj_meta_fast(L, tabref(o1->gch.metatable), MM_eq);
287 if (mo) {
288 TValue *top;
289 int it;
290 if (tabref(o1->gch.metatable) != tabref(o2->gch.metatable)) {
291 cTValue *mo2 = lj_meta_fast(L, tabref(o2->gch.metatable), MM_eq);
292 if (mo2 == NULL || !lj_obj_equal(mo, mo2))
293 return cast(TValue *, (intptr_t)ne);
294 }
295 top = curr_top(L);
296 setcont(top, ne ? lj_cont_condf : lj_cont_condt);
297 copyTV(L, top+1, mo);
298 it = o1->gch.gct == ~LJ_TTAB ? LJ_TTAB : LJ_TUDATA;
299 setgcV(L, top+2, &o1->gch, it);
300 setgcV(L, top+3, &o2->gch, it);
301 return top+2; /* Trigger metamethod call. */
302 }
303 return cast(TValue *, (intptr_t)ne);
304}
305
306/* Helper for ordered comparisons. String compare, __lt/__le metamethods. */
307TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op)
308{
309 if (itype(o1) == itype(o2)) { /* Never called with two numbers. */
310 if (tvisstr(o1) && tvisstr(o2)) {
311 int32_t res = lj_str_cmp(strV(o1), strV(o2));
312 return cast(TValue *, (intptr_t)(((op&2) ? res <= 0 : res < 0) ^ (op&1)));
313 } else {
314 trymt:
315 while (1) {
316 ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt;
317 MMS mm = (op & 2) ? MM_le : MM_lt;
318 cTValue *mo = lj_meta_lookup(L, o1, mm);
319 cTValue *mo2 = lj_meta_lookup(L, o2, mm);
320 if (tvisnil(mo) || !lj_obj_equal(mo, mo2)) {
321 if (op & 2) { /* MM_le not found: retry with MM_lt. */
322 cTValue *ot = o1; o1 = o2; o2 = ot; /* Swap operands. */
323 op ^= 3; /* Use LT and flip condition. */
324 continue;
325 }
326 goto err;
327 }
328 return mmcall(L, cont, mo, o1, o2);
329 }
330 }
331 } else if (tvisbool(o1) && tvisbool(o2)) {
332 goto trymt;
333 } else {
334 err:
335 lj_err_comp(L, o1, o2);
336 return NULL;
337 }
338}
339
340/* Helper for calls. __call metamethod. */
341void lj_meta_call(lua_State *L, TValue *func, TValue *top)
342{
343 cTValue *mo = lj_meta_lookup(L, func, MM_call);
344 TValue *p;
345 if (!tvisfunc(mo))
346 lj_err_optype_call(L, func);
347 for (p = top; p > func; p--) copyTV(L, p, p-1);
348 copyTV(L, func, mo);
349}
350
351/* Helper for FORI. Coercion. */
352void lj_meta_for(lua_State *L, TValue *base)
353{
354 if (!str2num(base, base)) lj_err_msg(L, LJ_ERR_FORINIT);
355 if (!str2num(base+1, base+1)) lj_err_msg(L, LJ_ERR_FORLIM);
356 if (!str2num(base+2, base+2)) lj_err_msg(L, LJ_ERR_FORSTEP);
357}
358