DUALNUM: Add integer type to core VM.
[luajit-2.0.git] / src / lj_meta.c
blob32024e859c0a42f9bdfcf00a36fedabf98bf53e1
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 */
9 #define lj_meta_c
10 #define LUA_CORE
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"
21 /* -- Metamethod handling ------------------------------------------------- */
23 /* String interning of metamethod names for fast indexing. */
24 void lj_meta_init(lua_State *L)
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 mm;
32 for (mm = 0, p = metanames; *p; mm++, 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 /* NOBARRIER: g->gcroot[] is a GC root. */
37 setgcref(g->gcroot[GCROOT_MMNAME+mm], obj2gco(s));
41 /* Negative caching of a few fast metamethods. See the lj_meta_fast() macro. */
42 cTValue *lj_meta_cache(GCtab *mt, MMS mm, GCstr *name)
44 cTValue *mo = lj_tab_getstr(mt, name);
45 lua_assert(mm <= MM_FAST);
46 if (!mo || tvisnil(mo)) { /* No metamethod? */
47 mt->nomm |= (uint8_t)(1u<<mm); /* Set negative cache flag. */
48 return NULL;
50 return mo;
53 /* Lookup metamethod for object. */
54 cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm)
56 GCtab *mt;
57 if (tvistab(o))
58 mt = tabref(tabV(o)->metatable);
59 else if (tvisudata(o))
60 mt = tabref(udataV(o)->metatable);
61 else
62 mt = tabref(basemt_obj(G(L), o));
63 if (mt) {
64 cTValue *mo = lj_tab_getstr(mt, mmname_str(G(L), mm));
65 if (mo)
66 return mo;
68 return niltv(L);
71 /* Setup call to metamethod to be run by Assembler VM. */
72 static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo,
73 cTValue *a, cTValue *b)
76 ** |-- framesize -> top top+1 top+2 top+3
77 ** before: [func slots ...]
78 ** mm setup: [func slots ...] [cont|?] [mo|tmtype] [a] [b]
79 ** in asm: [func slots ...] [cont|PC] [mo|delta] [a] [b]
80 ** ^-- func base ^-- mm base
81 ** after mm: [func slots ...] [result]
82 ** ^-- copy to base[PC_RA] --/ for lj_cont_ra
83 ** istruecond + branch for lj_cont_cond*
84 ** ignore for lj_cont_nop
85 ** next PC: [func slots ...]
87 TValue *top = L->top;
88 if (curr_funcisL(L)) top = curr_topL(L);
89 setcont(top, cont); /* Assembler VM stores PC in upper word. */
90 copyTV(L, top+1, mo); /* Store metamethod and two arguments. */
91 copyTV(L, top+2, a);
92 copyTV(L, top+3, b);
93 return top+2; /* Return new base. */
96 /* -- C helpers for some instructions, called from assembler VM ----------- */
98 /* Helper for TGET*. __index chain and metamethod. */
99 cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k)
101 int loop;
102 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) {
103 cTValue *mo;
104 if (tvistab(o)) {
105 GCtab *t = tabV(o);
106 cTValue *tv = lj_tab_get(L, t, k);
107 if (!tvisnil(tv) ||
108 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_index)))
109 return tv;
110 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_index))) {
111 lj_err_optype(L, o, LJ_ERR_OPINDEX);
112 return NULL; /* unreachable */
114 if (tvisfunc(mo)) {
115 L->top = mmcall(L, lj_cont_ra, mo, o, k);
116 return NULL; /* Trigger metamethod call. */
118 o = mo;
120 lj_err_msg(L, LJ_ERR_GETLOOP);
121 return NULL; /* unreachable */
124 /* Helper for TSET*. __newindex chain and metamethod. */
125 TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k)
127 TValue tmp;
128 int loop;
129 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) {
130 cTValue *mo;
131 if (tvistab(o)) {
132 GCtab *t = tabV(o);
133 TValue *tv = lj_tab_set(L, t, k);
134 if (!tvisnil(tv) ||
135 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) {
136 lj_gc_anybarriert(L, t);
137 return tv;
139 } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) {
140 lj_err_optype(L, o, LJ_ERR_OPINDEX);
141 return NULL; /* unreachable */
143 if (tvisfunc(mo)) {
144 L->top = mmcall(L, lj_cont_nop, mo, o, k);
145 /* L->top+2 = v filled in by caller. */
146 return NULL; /* Trigger metamethod call. */
148 copyTV(L, &tmp, mo);
149 o = &tmp;
151 lj_err_msg(L, LJ_ERR_SETLOOP);
152 return NULL; /* unreachable */
155 static cTValue *str2num(cTValue *o, TValue *n)
157 if (tvisnum(o))
158 return o;
159 else if (tvisint(o))
160 return (setnumV(n, (lua_Number)intV(o)), n);
161 else if (tvisstr(o) && lj_str_tonum(strV(o), n))
162 return n;
163 else
164 return NULL;
167 /* Helper for arithmetic instructions. Coercion, metamethod. */
168 TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc,
169 BCReg op)
171 MMS mm = bcmode_mm(op);
172 TValue tempb, tempc;
173 cTValue *b, *c;
174 if ((b = str2num(rb, &tempb)) != NULL &&
175 (c = str2num(rc, &tempc)) != NULL) { /* Try coercion first. */
176 setnumV(ra, lj_vm_foldarith(numV(b), numV(c), (int)mm-MM_add));
177 return NULL;
178 } else {
179 cTValue *mo = lj_meta_lookup(L, rb, mm);
180 if (tvisnil(mo)) {
181 mo = lj_meta_lookup(L, rc, mm);
182 if (tvisnil(mo)) {
183 if (str2num(rb, &tempb) == NULL) rc = rb;
184 lj_err_optype(L, rc, LJ_ERR_OPARITH);
185 return NULL; /* unreachable */
188 return mmcall(L, lj_cont_ra, mo, rb, rc);
192 /* In-place coercion of a number to a string. */
193 static LJ_AINLINE int tostring(lua_State *L, TValue *o)
195 if (tvisstr(o)) {
196 return 1;
197 } else if (tvisnumber(o)) {
198 setstrV(L, o, lj_str_fromnumber(L, o));
199 return 1;
200 } else {
201 return 0;
205 /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */
206 TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
208 do {
209 int n = 1;
210 if (!(tvisstr(top-1) || tvisnumber(top-1)) || !tostring(L, top)) {
211 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat);
212 if (tvisnil(mo)) {
213 mo = lj_meta_lookup(L, top, MM_concat);
214 if (tvisnil(mo)) {
215 if (tvisstr(top-1) || tvisnumber(top-1)) top++;
216 lj_err_optype(L, top-1, LJ_ERR_OPCAT);
217 return NULL; /* unreachable */
220 /* One of the top two elements is not a string, call __cat metamethod:
222 ** before: [...][CAT stack .........................]
223 ** top-1 top top+1 top+2
224 ** pick two: [...][CAT stack ...] [o1] [o2]
225 ** setup mm: [...][CAT stack ...] [cont|?] [mo|tmtype] [o1] [o2]
226 ** in asm: [...][CAT stack ...] [cont|PC] [mo|delta] [o1] [o2]
227 ** ^-- func base ^-- mm base
228 ** after mm: [...][CAT stack ...] <--push-- [result]
229 ** next step: [...][CAT stack .............]
231 copyTV(L, top+2, top); /* Careful with the order of stack copies! */
232 copyTV(L, top+1, top-1);
233 copyTV(L, top, mo);
234 setcont(top-1, lj_cont_cat);
235 return top+1; /* Trigger metamethod call. */
236 } else if (strV(top)->len == 0) { /* Shortcut. */
237 (void)tostring(L, top-1);
238 } else {
239 /* Pick as many strings as possible from the top and concatenate them:
241 ** before: [...][CAT stack ...........................]
242 ** pick str: [...][CAT stack ...] [...... strings ......]
243 ** concat: [...][CAT stack ...] [result]
244 ** next step: [...][CAT stack ............]
246 MSize tlen = strV(top)->len;
247 char *buffer;
248 int i;
249 for (n = 1; n <= left && tostring(L, top-n); n++) {
250 MSize len = strV(top-n)->len;
251 if (len >= LJ_MAX_STR - tlen)
252 lj_err_msg(L, LJ_ERR_STROV);
253 tlen += len;
255 buffer = lj_str_needbuf(L, &G(L)->tmpbuf, tlen);
256 n--;
257 tlen = 0;
258 for (i = n; i >= 0; i--) {
259 MSize len = strV(top-i)->len;
260 memcpy(buffer + tlen, strVdata(top-i), len);
261 tlen += len;
263 setstrV(L, top-n, lj_str_new(L, buffer, tlen));
265 left -= n;
266 top -= n;
267 } while (left >= 1);
268 lj_gc_check_fixtop(L);
269 return NULL;
272 /* Helper for LEN. __len metamethod. */
273 TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o)
275 cTValue *mo = lj_meta_lookup(L, o, MM_len);
276 if (tvisnil(mo)) {
277 lj_err_optype(L, o, LJ_ERR_OPLEN);
278 return NULL; /* unreachable */
280 return mmcall(L, lj_cont_ra, mo, o, niltv(L));
283 /* Helper for equality comparisons. __eq metamethod. */
284 TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne)
286 /* Field metatable must be at same offset for GCtab and GCudata! */
287 cTValue *mo = lj_meta_fast(L, tabref(o1->gch.metatable), MM_eq);
288 if (mo) {
289 TValue *top;
290 uint32_t it;
291 if (tabref(o1->gch.metatable) != tabref(o2->gch.metatable)) {
292 cTValue *mo2 = lj_meta_fast(L, tabref(o2->gch.metatable), MM_eq);
293 if (mo2 == NULL || !lj_obj_equal(mo, mo2))
294 return cast(TValue *, (intptr_t)ne);
296 top = curr_top(L);
297 setcont(top, ne ? lj_cont_condf : lj_cont_condt);
298 copyTV(L, top+1, mo);
299 it = ~(uint32_t)o1->gch.gct;
300 setgcV(L, top+2, o1, it);
301 setgcV(L, top+3, o2, it);
302 return top+2; /* Trigger metamethod call. */
304 return cast(TValue *, (intptr_t)ne);
307 #if LJ_HASFFI
308 TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins)
310 ASMFunction cont = (bc_op(ins) & 1) ? lj_cont_condf : lj_cont_condt;
311 int op = (int)bc_op(ins) & ~1;
312 TValue tv;
313 cTValue *mo, *o2, *o1 = &L->base[bc_a(ins)];
314 cTValue *o1mm = o1;
315 if (op == BC_ISEQV) {
316 o2 = &L->base[bc_d(ins)];
317 if (!tviscdata(o1mm)) o1mm = o2;
318 } else if (op == BC_ISEQS) {
319 setstrV(L, &tv, gco2str(proto_kgc(curr_proto(L), ~(ptrdiff_t)bc_d(ins))));
320 o2 = &tv;
321 } else if (op == BC_ISEQN) {
322 o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)];
323 } else {
324 lua_assert(op == BC_ISEQP);
325 setitype(&tv, ~bc_d(ins));
326 o2 = &tv;
328 mo = lj_meta_lookup(L, o1mm, MM_eq);
329 if (LJ_LIKELY(!tvisnil(mo)))
330 return mmcall(L, cont, mo, o1, o2);
331 else
332 return cast(TValue *, (intptr_t)(bc_op(ins) & 1));
334 #endif
336 /* Helper for ordered comparisons. String compare, __lt/__le metamethods. */
337 TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op)
339 if (LJ_HASFFI && (tviscdata(o1) || tviscdata(o2))) {
340 ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt;
341 MMS mm = (op & 2) ? MM_le : MM_lt;
342 cTValue *mo = lj_meta_lookup(L, tviscdata(o1) ? o1 : o2, mm);
343 if (LJ_UNLIKELY(tvisnil(mo))) goto err;
344 return mmcall(L, cont, mo, o1, o2);
345 } else if (itype(o1) == itype(o2)) { /* Never called with two numbers. */
346 if (tvisstr(o1) && tvisstr(o2)) {
347 int32_t res = lj_str_cmp(strV(o1), strV(o2));
348 return cast(TValue *, (intptr_t)(((op&2) ? res <= 0 : res < 0) ^ (op&1)));
349 } else {
350 trymt:
351 while (1) {
352 ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt;
353 MMS mm = (op & 2) ? MM_le : MM_lt;
354 cTValue *mo = lj_meta_lookup(L, o1, mm);
355 cTValue *mo2 = lj_meta_lookup(L, o2, mm);
356 if (tvisnil(mo) || !lj_obj_equal(mo, mo2)) {
357 if (op & 2) { /* MM_le not found: retry with MM_lt. */
358 cTValue *ot = o1; o1 = o2; o2 = ot; /* Swap operands. */
359 op ^= 3; /* Use LT and flip condition. */
360 continue;
362 goto err;
364 return mmcall(L, cont, mo, o1, o2);
367 } else if (tvisbool(o1) && tvisbool(o2)) {
368 goto trymt;
369 } else {
370 err:
371 lj_err_comp(L, o1, o2);
372 return NULL;
376 /* Helper for calls. __call metamethod. */
377 void lj_meta_call(lua_State *L, TValue *func, TValue *top)
379 cTValue *mo = lj_meta_lookup(L, func, MM_call);
380 TValue *p;
381 if (!tvisfunc(mo))
382 lj_err_optype_call(L, func);
383 for (p = top; p > func; p--) copyTV(L, p, p-1);
384 copyTV(L, func, mo);
387 /* Helper for FORI. Coercion. */
388 void LJ_FASTCALL lj_meta_for(lua_State *L, TValue *base)
390 if (!str2num(base, base)) lj_err_msg(L, LJ_ERR_FORINIT);
391 if (!str2num(base+1, base+1)) lj_err_msg(L, LJ_ERR_FORLIM);
392 if (!str2num(base+2, base+2)) lj_err_msg(L, LJ_ERR_FORSTEP);