aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/luajit-2.0/src/lj_meta.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/luajit-2.0/src/lj_meta.c')
-rw-r--r--libraries/luajit-2.0/src/lj_meta.c463
1 files changed, 0 insertions, 463 deletions
diff --git a/libraries/luajit-2.0/src/lj_meta.c b/libraries/luajit-2.0/src/lj_meta.c
deleted file mode 100644
index f258e3e..0000000
--- a/libraries/luajit-2.0/src/lj_meta.c
+++ /dev/null
@@ -1,463 +0,0 @@
1/*
2** Metamethod handling.
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*/
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_frame.h"
19#include "lj_bc.h"
20#include "lj_vm.h"
21
22/* -- Metamethod handling ------------------------------------------------- */
23
24/* String interning of metamethod names for fast indexing. */
25void lj_meta_init(lua_State *L)
26{
27#define MMNAME(name) "__" #name
28 const char *metanames = MMDEF(MMNAME);
29#undef MMNAME
30 global_State *g = G(L);
31 const char *p, *q;
32 uint32_t mm;
33 for (mm = 0, p = metanames; *p; mm++, p = q) {
34 GCstr *s;
35 for (q = p+2; *q && *q != '_'; q++) ;
36 s = lj_str_new(L, p, (size_t)(q-p));
37 /* NOBARRIER: g->gcroot[] is a GC root. */
38 setgcref(g->gcroot[GCROOT_MMNAME+mm], 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 |= (uint8_t)(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(basemt_obj(G(L), o));
64 if (mt) {
65 cTValue *mo = lj_tab_getstr(mt, mmname_str(G(L), mm));
66 if (mo)
67 return mo;
68 }
69 return niltv(L);
70}
71
72#if LJ_HASFFI
73/* Tailcall from C function. */
74int lj_meta_tailcall(lua_State *L, cTValue *tv)
75{
76 TValue *base = L->base;
77 TValue *top = L->top;
78 const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */
79 copyTV(L, base-1, tv); /* Replace frame with new object. */
80 top->u32.lo = LJ_CONT_TAILCALL;
81 setframe_pc(top, pc);
82 setframe_gc(top+1, obj2gco(L)); /* Dummy frame object. */
83 setframe_ftsz(top+1, (int)((char *)(top+2) - (char *)base) + FRAME_CONT);
84 L->base = L->top = top+2;
85 /*
86 ** before: [old_mo|PC] [... ...]
87 ** ^base ^top
88 ** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta]
89 ** ^base/top
90 ** tailcall: [new_mo|PC] [... ...]
91 ** ^base ^top
92 */
93 return 0;
94}
95#endif
96
97/* Setup call to metamethod to be run by Assembler VM. */
98static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo,
99 cTValue *a, cTValue *b)
100{
101 /*
102 ** |-- framesize -> top top+1 top+2 top+3
103 ** before: [func slots ...]
104 ** mm setup: [func slots ...] [cont|?] [mo|tmtype] [a] [b]
105 ** in asm: [func slots ...] [cont|PC] [mo|delta] [a] [b]
106 ** ^-- func base ^-- mm base
107 ** after mm: [func slots ...] [result]
108 ** ^-- copy to base[PC_RA] --/ for lj_cont_ra
109 ** istruecond + branch for lj_cont_cond*
110 ** ignore for lj_cont_nop
111 ** next PC: [func slots ...]
112 */
113 TValue *top = L->top;
114 if (curr_funcisL(L)) top = curr_topL(L);
115 setcont(top, cont); /* Assembler VM stores PC in upper word. */
116 copyTV(L, top+1, mo); /* Store metamethod and two arguments. */
117 copyTV(L, top+2, a);
118 copyTV(L, top+3, b);
119 return top+2; /* Return new base. */
120}
121
122/* -- C helpers for some instructions, called from assembler VM ----------- */
123
124/* Helper for TGET*. __index chain and metamethod. */
125cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k)
126{
127 int loop;
128 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) {
129 cTValue *mo;
130 if (LJ_LIKELY(tvistab(o))) {
131 GCtab *t = tabV(o);
132 cTValue *tv = lj_tab_get(L, t, k);
133 if (!tvisnil(tv) ||
134 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_index)))
135 return tv;
136 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_index))) {
137 lj_err_optype(L, o, LJ_ERR_OPINDEX);
138 return NULL; /* unreachable */
139 }
140 if (tvisfunc(mo)) {
141 L->top = mmcall(L, lj_cont_ra, mo, o, k);
142 return NULL; /* Trigger metamethod call. */
143 }
144 o = mo;
145 }
146 lj_err_msg(L, LJ_ERR_GETLOOP);
147 return NULL; /* unreachable */
148}
149
150/* Helper for TSET*. __newindex chain and metamethod. */
151TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k)
152{
153 TValue tmp;
154 int loop;
155 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) {
156 cTValue *mo;
157 if (LJ_LIKELY(tvistab(o))) {
158 GCtab *t = tabV(o);
159 cTValue *tv = lj_tab_get(L, t, k);
160 if (LJ_LIKELY(!tvisnil(tv))) {
161 t->nomm = 0; /* Invalidate negative metamethod cache. */
162 lj_gc_anybarriert(L, t);
163 return (TValue *)tv;
164 } else if (!(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) {
165 t->nomm = 0; /* Invalidate negative metamethod cache. */
166 lj_gc_anybarriert(L, t);
167 if (tv != niltv(L))
168 return (TValue *)tv;
169 if (tvisnil(k)) lj_err_msg(L, LJ_ERR_NILIDX);
170 else if (tvisint(k)) { setnumV(&tmp, (lua_Number)intV(k)); k = &tmp; }
171 else if (tvisnum(k) && tvisnan(k)) lj_err_msg(L, LJ_ERR_NANIDX);
172 return lj_tab_newkey(L, t, k);
173 }
174 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) {
175 lj_err_optype(L, o, LJ_ERR_OPINDEX);
176 return NULL; /* unreachable */
177 }
178 if (tvisfunc(mo)) {
179 L->top = mmcall(L, lj_cont_nop, mo, o, k);
180 /* L->top+2 = v filled in by caller. */
181 return NULL; /* Trigger metamethod call. */
182 }
183 copyTV(L, &tmp, mo);
184 o = &tmp;
185 }
186 lj_err_msg(L, LJ_ERR_SETLOOP);
187 return NULL; /* unreachable */
188}
189
190static cTValue *str2num(cTValue *o, TValue *n)
191{
192 if (tvisnum(o))
193 return o;
194 else if (tvisint(o))
195 return (setnumV(n, (lua_Number)intV(o)), n);
196 else if (tvisstr(o) && lj_str_tonum(strV(o), n))
197 return n;
198 else
199 return NULL;
200}
201
202/* Helper for arithmetic instructions. Coercion, metamethod. */
203TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc,
204 BCReg op)
205{
206 MMS mm = bcmode_mm(op);
207 TValue tempb, tempc;
208 cTValue *b, *c;
209 if ((b = str2num(rb, &tempb)) != NULL &&
210 (c = str2num(rc, &tempc)) != NULL) { /* Try coercion first. */
211 setnumV(ra, lj_vm_foldarith(numV(b), numV(c), (int)mm-MM_add));
212 return NULL;
213 } else {
214 cTValue *mo = lj_meta_lookup(L, rb, mm);
215 if (tvisnil(mo)) {
216 mo = lj_meta_lookup(L, rc, mm);
217 if (tvisnil(mo)) {
218 if (str2num(rb, &tempb) == NULL) rc = rb;
219 lj_err_optype(L, rc, LJ_ERR_OPARITH);
220 return NULL; /* unreachable */
221 }
222 }
223 return mmcall(L, lj_cont_ra, mo, rb, rc);
224 }
225}
226
227/* In-place coercion of a number to a string. */
228static LJ_AINLINE int tostring(lua_State *L, TValue *o)
229{
230 if (tvisstr(o)) {
231 return 1;
232 } else if (tvisnumber(o)) {
233 setstrV(L, o, lj_str_fromnumber(L, o));
234 return 1;
235 } else {
236 return 0;
237 }
238}
239
240/* Helper for CAT. Coercion, iterative concat, __concat metamethod. */
241TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
242{
243 do {
244 int n = 1;
245 if (!(tvisstr(top-1) || tvisnumber(top-1)) || !tostring(L, top)) {
246 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat);
247 if (tvisnil(mo)) {
248 mo = lj_meta_lookup(L, top, MM_concat);
249 if (tvisnil(mo)) {
250 if (tvisstr(top-1) || tvisnumber(top-1)) top++;
251 lj_err_optype(L, top-1, LJ_ERR_OPCAT);
252 return NULL; /* unreachable */
253 }
254 }
255 /* One of the top two elements is not a string, call __cat metamethod:
256 **
257 ** before: [...][CAT stack .........................]
258 ** top-1 top top+1 top+2
259 ** pick two: [...][CAT stack ...] [o1] [o2]
260 ** setup mm: [...][CAT stack ...] [cont|?] [mo|tmtype] [o1] [o2]
261 ** in asm: [...][CAT stack ...] [cont|PC] [mo|delta] [o1] [o2]
262 ** ^-- func base ^-- mm base
263 ** after mm: [...][CAT stack ...] <--push-- [result]
264 ** next step: [...][CAT stack .............]
265 */
266 copyTV(L, top+2, top); /* Careful with the order of stack copies! */
267 copyTV(L, top+1, top-1);
268 copyTV(L, top, mo);
269 setcont(top-1, lj_cont_cat);
270 return top+1; /* Trigger metamethod call. */
271 } else if (strV(top)->len == 0) { /* Shortcut. */
272 (void)tostring(L, top-1);
273 } else {
274 /* Pick as many strings as possible from the top and concatenate them:
275 **
276 ** before: [...][CAT stack ...........................]
277 ** pick str: [...][CAT stack ...] [...... strings ......]
278 ** concat: [...][CAT stack ...] [result]
279 ** next step: [...][CAT stack ............]
280 */
281 MSize tlen = strV(top)->len;
282 char *buffer;
283 int i;
284 for (n = 1; n <= left && tostring(L, top-n); n++) {
285 MSize len = strV(top-n)->len;
286 if (len >= LJ_MAX_STR - tlen)
287 lj_err_msg(L, LJ_ERR_STROV);
288 tlen += len;
289 }
290 buffer = lj_str_needbuf(L, &G(L)->tmpbuf, tlen);
291 n--;
292 tlen = 0;
293 for (i = n; i >= 0; i--) {
294 MSize len = strV(top-i)->len;
295 memcpy(buffer + tlen, strVdata(top-i), len);
296 tlen += len;
297 }
298 setstrV(L, top-n, lj_str_new(L, buffer, tlen));
299 }
300 left -= n;
301 top -= n;
302 } while (left >= 1);
303 lj_gc_check_fixtop(L);
304 return NULL;
305}
306
307/* Helper for LEN. __len metamethod. */
308TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o)
309{
310 cTValue *mo = lj_meta_lookup(L, o, MM_len);
311 if (tvisnil(mo)) {
312#ifdef LUAJIT_ENABLE_LUA52COMPAT
313 if (tvistab(o))
314 tabref(tabV(o)->metatable)->nomm |= (uint8_t)(1u<<MM_len);
315 else
316#endif
317 lj_err_optype(L, o, LJ_ERR_OPLEN);
318 return NULL;
319 }
320#ifdef LUAJIT_ENABLE_LUA52COMPAT
321 return mmcall(L, lj_cont_ra, mo, o, o);
322#else
323 return mmcall(L, lj_cont_ra, mo, o, niltv(L));
324#endif
325}
326
327/* Helper for equality comparisons. __eq metamethod. */
328TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne)
329{
330 /* Field metatable must be at same offset for GCtab and GCudata! */
331 cTValue *mo = lj_meta_fast(L, tabref(o1->gch.metatable), MM_eq);
332 if (mo) {
333 TValue *top;
334 uint32_t it;
335 if (tabref(o1->gch.metatable) != tabref(o2->gch.metatable)) {
336 cTValue *mo2 = lj_meta_fast(L, tabref(o2->gch.metatable), MM_eq);
337 if (mo2 == NULL || !lj_obj_equal(mo, mo2))
338 return (TValue *)(intptr_t)ne;
339 }
340 top = curr_top(L);
341 setcont(top, ne ? lj_cont_condf : lj_cont_condt);
342 copyTV(L, top+1, mo);
343 it = ~(uint32_t)o1->gch.gct;
344 setgcV(L, top+2, o1, it);
345 setgcV(L, top+3, o2, it);
346 return top+2; /* Trigger metamethod call. */
347 }
348 return (TValue *)(intptr_t)ne;
349}
350
351#if LJ_HASFFI
352TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins)
353{
354 ASMFunction cont = (bc_op(ins) & 1) ? lj_cont_condf : lj_cont_condt;
355 int op = (int)bc_op(ins) & ~1;
356 TValue tv;
357 cTValue *mo, *o2, *o1 = &L->base[bc_a(ins)];
358 cTValue *o1mm = o1;
359 if (op == BC_ISEQV) {
360 o2 = &L->base[bc_d(ins)];
361 if (!tviscdata(o1mm)) o1mm = o2;
362 } else if (op == BC_ISEQS) {
363 setstrV(L, &tv, gco2str(proto_kgc(curr_proto(L), ~(ptrdiff_t)bc_d(ins))));
364 o2 = &tv;
365 } else if (op == BC_ISEQN) {
366 o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)];
367 } else {
368 lua_assert(op == BC_ISEQP);
369 setitype(&tv, ~bc_d(ins));
370 o2 = &tv;
371 }
372 mo = lj_meta_lookup(L, o1mm, MM_eq);
373 if (LJ_LIKELY(!tvisnil(mo)))
374 return mmcall(L, cont, mo, o1, o2);
375 else
376 return (TValue *)(intptr_t)(bc_op(ins) & 1);
377}
378#endif
379
380/* Helper for ordered comparisons. String compare, __lt/__le metamethods. */
381TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op)
382{
383 if (LJ_HASFFI && (tviscdata(o1) || tviscdata(o2))) {
384 ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt;
385 MMS mm = (op & 2) ? MM_le : MM_lt;
386 cTValue *mo = lj_meta_lookup(L, tviscdata(o1) ? o1 : o2, mm);
387 if (LJ_UNLIKELY(tvisnil(mo))) goto err;
388 return mmcall(L, cont, mo, o1, o2);
389 } else if (itype(o1) == itype(o2)) { /* Never called with two numbers. */
390 if (tvisstr(o1) && tvisstr(o2)) {
391 int32_t res = lj_str_cmp(strV(o1), strV(o2));
392 return (TValue *)(intptr_t)(((op&2) ? res <= 0 : res < 0) ^ (op&1));
393 } else {
394 trymt:
395 while (1) {
396 ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt;
397 MMS mm = (op & 2) ? MM_le : MM_lt;
398 cTValue *mo = lj_meta_lookup(L, o1, mm);
399 cTValue *mo2 = lj_meta_lookup(L, o2, mm);
400 if (tvisnil(mo) || !lj_obj_equal(mo, mo2)) {
401 if (op & 2) { /* MM_le not found: retry with MM_lt. */
402 cTValue *ot = o1; o1 = o2; o2 = ot; /* Swap operands. */
403 op ^= 3; /* Use LT and flip condition. */
404 continue;
405 }
406 goto err;
407 }
408 return mmcall(L, cont, mo, o1, o2);
409 }
410 }
411 } else if (tvisbool(o1) && tvisbool(o2)) {
412 goto trymt;
413 } else {
414 err:
415 lj_err_comp(L, o1, o2);
416 return NULL;
417 }
418}
419
420/* Helper for calls. __call metamethod. */
421void lj_meta_call(lua_State *L, TValue *func, TValue *top)
422{
423 cTValue *mo = lj_meta_lookup(L, func, MM_call);
424 TValue *p;
425 if (!tvisfunc(mo))
426 lj_err_optype_call(L, func);
427 for (p = top; p > func; p--) copyTV(L, p, p-1);
428 copyTV(L, func, mo);
429}
430
431/* Helper for FORI. Coercion. */
432void LJ_FASTCALL lj_meta_for(lua_State *L, TValue *o)
433{
434 if (!(tvisnumber(o) || (tvisstr(o) && lj_str_tonumber(strV(o), o))))
435 lj_err_msg(L, LJ_ERR_FORINIT);
436 if (!(tvisnumber(o+1) || (tvisstr(o+1) && lj_str_tonumber(strV(o+1), o+1))))
437 lj_err_msg(L, LJ_ERR_FORLIM);
438 if (!(tvisnumber(o+2) || (tvisstr(o+2) && lj_str_tonumber(strV(o+2), o+2))))
439 lj_err_msg(L, LJ_ERR_FORSTEP);
440 if (LJ_DUALNUM) {
441 /* Ensure all slots are integers or all slots are numbers. */
442 int32_t k[3];
443 int nint = 0;
444 ptrdiff_t i;
445 for (i = 0; i <= 2; i++) {
446 if (tvisint(o+i)) {
447 k[i] = intV(o+i); nint++;
448 } else {
449 k[i] = lj_num2int(numV(o+i)); nint += ((lua_Number)k[i] == numV(o+i));
450 }
451 }
452 if (nint == 3) { /* Narrow to integers. */
453 setintV(o, k[0]);
454 setintV(o+1, k[1]);
455 setintV(o+2, k[2]);
456 } else if (nint != 0) { /* Widen to numbers. */
457 if (tvisint(o)) setnumV(o, (lua_Number)intV(o));
458 if (tvisint(o+1)) setnumV(o+1, (lua_Number)intV(o+1));
459 if (tvisint(o+2)) setnumV(o+2, (lua_Number)intV(o+2));
460 }
461 }
462}
463