2 ** Metamethod handling.
3 ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
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
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
);
29 global_State
*g
= G(L
);
32 for (mm
= 0, p
= metanames
; *p
; mm
++, p
= q
) {
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. */
53 /* Lookup metamethod for object. */
54 cTValue
*lj_meta_lookup(lua_State
*L
, cTValue
*o
, MMS mm
)
58 mt
= tabref(tabV(o
)->metatable
);
59 else if (tvisudata(o
))
60 mt
= tabref(udataV(o
)->metatable
);
62 mt
= tabref(basemt_obj(G(L
), o
));
64 cTValue
*mo
= lj_tab_getstr(mt
, mmname_str(G(L
), mm
));
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 ...]
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. */
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
)
102 for (loop
= 0; loop
< LJ_MAX_IDXCHAIN
; loop
++) {
106 cTValue
*tv
= lj_tab_get(L
, t
, k
);
108 !(mo
= lj_meta_fast(L
, tabref(t
->metatable
), MM_index
)))
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 */
115 L
->top
= mmcall(L
, lj_cont_ra
, mo
, o
, k
);
116 return NULL
; /* Trigger metamethod call. */
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
)
129 for (loop
= 0; loop
< LJ_MAX_IDXCHAIN
; loop
++) {
133 TValue
*tv
= lj_tab_set(L
, t
, k
);
135 !(mo
= lj_meta_fast(L
, tabref(t
->metatable
), MM_newindex
))) {
136 lj_gc_anybarriert(L
, t
);
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 */
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. */
151 lj_err_msg(L
, LJ_ERR_SETLOOP
);
152 return NULL
; /* unreachable */
155 static cTValue
*str2num(cTValue
*o
, TValue
*n
)
160 return (setnumV(n
, (lua_Number
)intV(o
)), n
);
161 else if (tvisstr(o
) && lj_str_tonum(strV(o
), n
))
167 /* Helper for arithmetic instructions. Coercion, metamethod. */
168 TValue
*lj_meta_arith(lua_State
*L
, TValue
*ra
, cTValue
*rb
, cTValue
*rc
,
171 MMS mm
= bcmode_mm(op
);
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
));
179 cTValue
*mo
= lj_meta_lookup(L
, rb
, mm
);
181 mo
= lj_meta_lookup(L
, rc
, mm
);
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
)
197 } else if (tvisnumber(o
)) {
198 setstrV(L
, o
, lj_str_fromnumber(L
, o
));
205 /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */
206 TValue
*lj_meta_cat(lua_State
*L
, TValue
*top
, int left
)
210 if (!(tvisstr(top
-1) || tvisnumber(top
-1)) || !tostring(L
, top
)) {
211 cTValue
*mo
= lj_meta_lookup(L
, top
-1, MM_concat
);
213 mo
= lj_meta_lookup(L
, top
, MM_concat
);
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);
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);
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
;
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
);
255 buffer
= lj_str_needbuf(L
, &G(L
)->tmpbuf
, tlen
);
258 for (i
= n
; i
>= 0; i
--) {
259 MSize len
= strV(top
-i
)->len
;
260 memcpy(buffer
+ tlen
, strVdata(top
-i
), len
);
263 setstrV(L
, top
-n
, lj_str_new(L
, buffer
, tlen
));
268 lj_gc_check_fixtop(L
);
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
);
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
);
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
);
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
);
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;
313 cTValue
*mo
, *o2
, *o1
= &L
->base
[bc_a(ins
)];
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
))));
321 } else if (op
== BC_ISEQN
) {
322 o2
= &mref(curr_proto(L
)->k
, cTValue
)[bc_d(ins
)];
324 lua_assert(op
== BC_ISEQP
);
325 setitype(&tv
, ~bc_d(ins
));
328 mo
= lj_meta_lookup(L
, o1mm
, MM_eq
);
329 if (LJ_LIKELY(!tvisnil(mo
)))
330 return mmcall(L
, cont
, mo
, o1
, o2
);
332 return cast(TValue
*, (intptr_t)(bc_op(ins
) & 1));
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)));
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. */
364 return mmcall(L
, cont
, mo
, o1
, o2
);
367 } else if (tvisbool(o1
) && tvisbool(o2
)) {
371 lj_err_comp(L
, o1
, o2
);
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
);
382 lj_err_optype_call(L
, func
);
383 for (p
= top
; p
> func
; p
--) copyTV(L
, p
, p
-1);
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
);