2 ** Metamethod handling.
3 ** Copyright (C) 2005-2025 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
22 #include "lj_strscan.h"
23 #include "lj_strfmt.h"
26 /* -- Metamethod handling ------------------------------------------------- */
28 /* String interning of metamethod names for fast indexing. */
29 void lj_meta_init(lua_State
*L
)
31 #define MMNAME(name) "__" #name
32 const char *metanames
= MMDEF(MMNAME
);
34 global_State
*g
= G(L
);
37 for (mm
= 0, p
= metanames
; *p
; mm
++, p
= q
) {
39 for (q
= p
+2; *q
&& *q
!= '_'; q
++) ;
40 s
= lj_str_new(L
, p
, (size_t)(q
-p
));
41 /* NOBARRIER: g->gcroot[] is a GC root. */
42 setgcref(g
->gcroot
[GCROOT_MMNAME
+mm
], obj2gco(s
));
46 /* Negative caching of a few fast metamethods. See the lj_meta_fast() macro. */
47 cTValue
*lj_meta_cache(GCtab
*mt
, MMS mm
, GCstr
*name
)
49 cTValue
*mo
= lj_tab_getstr(mt
, name
);
50 lj_assertX(mm
<= MM_FAST
, "bad metamethod %d", mm
);
51 if (!mo
|| tvisnil(mo
)) { /* No metamethod? */
52 mt
->nomm
|= (uint8_t)(1u<<mm
); /* Set negative cache flag. */
58 /* Lookup metamethod for object. */
59 cTValue
*lj_meta_lookup(lua_State
*L
, cTValue
*o
, MMS mm
)
63 mt
= tabref(tabV(o
)->metatable
);
64 else if (tvisudata(o
))
65 mt
= tabref(udataV(o
)->metatable
);
67 mt
= tabref(basemt_obj(G(L
), o
));
69 cTValue
*mo
= lj_tab_getstr(mt
, mmname_str(G(L
), mm
));
77 /* Tailcall from C function. */
78 int lj_meta_tailcall(lua_State
*L
, cTValue
*tv
)
80 TValue
*base
= L
->base
;
82 const BCIns
*pc
= frame_pc(base
-1); /* Preserve old PC from frame. */
83 copyTV(L
, base
-1-LJ_FR2
, tv
); /* Replace frame with new object. */
85 (top
++)->u64
= LJ_CONT_TAILCALL
;
87 top
->u32
.lo
= LJ_CONT_TAILCALL
;
88 setframe_pc(top
++, pc
);
89 setframe_gc(top
, obj2gco(L
), LJ_TTHREAD
); /* Dummy frame object. */
91 setframe_ftsz(top
, ((char *)(top
+1) - (char *)base
) + FRAME_CONT
);
92 L
->base
= L
->top
= top
+1;
94 ** before: [old_mo|PC] [... ...]
96 ** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta]
98 ** tailcall: [new_mo|PC] [... ...]
105 /* Setup call to metamethod to be run by Assembler VM. */
106 static TValue
*mmcall(lua_State
*L
, ASMFunction cont
, cTValue
*mo
,
107 cTValue
*a
, cTValue
*b
)
110 ** |-- framesize -> top top+1 top+2 top+3
111 ** before: [func slots ...]
112 ** mm setup: [func slots ...] [cont|?] [mo|tmtype] [a] [b]
113 ** in asm: [func slots ...] [cont|PC] [mo|delta] [a] [b]
114 ** ^-- func base ^-- mm base
115 ** after mm: [func slots ...] [result]
116 ** ^-- copy to base[PC_RA] --/ for lj_cont_ra
117 ** istruecond + branch for lj_cont_cond*
118 ** ignore for lj_cont_nop
119 ** next PC: [func slots ...]
121 TValue
*top
= L
->top
;
122 if (curr_funcisL(L
)) top
= curr_topL(L
);
123 setcont(top
++, cont
); /* Assembler VM stores PC in upper word or FR2. */
124 if (LJ_FR2
) setnilV(top
++);
125 copyTV(L
, top
++, mo
); /* Store metamethod and two arguments. */
126 if (LJ_FR2
) setnilV(top
++);
129 return top
; /* Return new base. */
132 /* -- C helpers for some instructions, called from assembler VM ----------- */
134 /* Helper for TGET*. __index chain and metamethod. */
135 cTValue
*lj_meta_tget(lua_State
*L
, cTValue
*o
, cTValue
*k
)
138 for (loop
= 0; loop
< LJ_MAX_IDXCHAIN
; loop
++) {
140 if (LJ_LIKELY(tvistab(o
))) {
142 cTValue
*tv
= lj_tab_get(L
, t
, k
);
144 !(mo
= lj_meta_fast(L
, tabref(t
->metatable
), MM_index
)))
146 } else if (tvisnil(mo
= lj_meta_lookup(L
, o
, MM_index
))) {
147 lj_err_optype(L
, o
, LJ_ERR_OPINDEX
);
148 return NULL
; /* unreachable */
151 L
->top
= mmcall(L
, lj_cont_ra
, mo
, o
, k
);
152 return NULL
; /* Trigger metamethod call. */
156 lj_err_msg(L
, LJ_ERR_GETLOOP
);
157 return NULL
; /* unreachable */
160 /* Helper for TSET*. __newindex chain and metamethod. */
161 TValue
*lj_meta_tset(lua_State
*L
, cTValue
*o
, cTValue
*k
)
165 for (loop
= 0; loop
< LJ_MAX_IDXCHAIN
; loop
++) {
167 if (LJ_LIKELY(tvistab(o
))) {
169 cTValue
*tv
= lj_tab_get(L
, t
, k
);
170 if (LJ_LIKELY(!tvisnil(tv
))) {
171 t
->nomm
= 0; /* Invalidate negative metamethod cache. */
172 lj_gc_anybarriert(L
, t
);
174 } else if (!(mo
= lj_meta_fast(L
, tabref(t
->metatable
), MM_newindex
))) {
175 t
->nomm
= 0; /* Invalidate negative metamethod cache. */
176 lj_gc_anybarriert(L
, t
);
179 if (tvisnil(k
)) lj_err_msg(L
, LJ_ERR_NILIDX
);
180 else if (tvisint(k
)) { setnumV(&tmp
, (lua_Number
)intV(k
)); k
= &tmp
; }
181 else if (tvisnum(k
) && tvisnan(k
)) lj_err_msg(L
, LJ_ERR_NANIDX
);
182 return lj_tab_newkey(L
, t
, k
);
184 } else if (tvisnil(mo
= lj_meta_lookup(L
, o
, MM_newindex
))) {
185 lj_err_optype(L
, o
, LJ_ERR_OPINDEX
);
186 return NULL
; /* unreachable */
189 L
->top
= mmcall(L
, lj_cont_nop
, mo
, o
, k
);
190 /* L->top+2 = v filled in by caller. */
191 return NULL
; /* Trigger metamethod call. */
196 lj_err_msg(L
, LJ_ERR_SETLOOP
);
197 return NULL
; /* unreachable */
200 static cTValue
*str2num(cTValue
*o
, TValue
*n
)
205 return (setnumV(n
, (lua_Number
)intV(o
)), n
);
206 else if (tvisstr(o
) && lj_strscan_num(strV(o
), n
))
212 /* Helper for arithmetic instructions. Coercion, metamethod. */
213 TValue
*lj_meta_arith(lua_State
*L
, TValue
*ra
, cTValue
*rb
, cTValue
*rc
,
216 MMS mm
= bcmode_mm(op
);
219 if ((b
= str2num(rb
, &tempb
)) != NULL
&&
220 (c
= str2num(rc
, &tempc
)) != NULL
) { /* Try coercion first. */
221 setnumV(ra
, lj_vm_foldarith(numV(b
), numV(c
), (int)mm
-MM_add
));
224 cTValue
*mo
= lj_meta_lookup(L
, rb
, mm
);
226 mo
= lj_meta_lookup(L
, rc
, mm
);
228 if (str2num(rb
, &tempb
) == NULL
) rc
= rb
;
229 lj_err_optype(L
, rc
, LJ_ERR_OPARITH
);
230 return NULL
; /* unreachable */
233 return mmcall(L
, lj_cont_ra
, mo
, rb
, rc
);
237 /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */
238 TValue
*lj_meta_cat(lua_State
*L
, TValue
*top
, int left
)
241 if (left
< 0) { left
= -left
; fromc
= 1; }
243 if (!(tvisstr(top
) || tvisnumber(top
) || tvisbuf(top
)) ||
244 !(tvisstr(top
-1) || tvisnumber(top
-1) || tvisbuf(top
-1))) {
245 cTValue
*mo
= lj_meta_lookup(L
, top
-1, MM_concat
);
247 mo
= lj_meta_lookup(L
, top
, MM_concat
);
249 if (tvisstr(top
-1) || tvisnumber(top
-1)) top
++;
250 lj_err_optype(L
, top
-1, LJ_ERR_OPCAT
);
251 return NULL
; /* unreachable */
254 /* One of the top two elements is not a string, call __cat metamethod:
256 ** before: [...][CAT stack .........................]
257 ** top-1 top top+1 top+2
258 ** pick two: [...][CAT stack ...] [o1] [o2]
259 ** setup mm: [...][CAT stack ...] [cont|?] [mo|tmtype] [o1] [o2]
260 ** in asm: [...][CAT stack ...] [cont|PC] [mo|delta] [o1] [o2]
261 ** ^-- func base ^-- mm base
262 ** after mm: [...][CAT stack ...] <--push-- [result]
263 ** next step: [...][CAT stack .............]
265 copyTV(L
, top
+2*LJ_FR2
+2, top
); /* Carefully ordered stack copies! */
266 copyTV(L
, top
+2*LJ_FR2
+1, top
-1);
267 copyTV(L
, top
+LJ_FR2
, mo
);
268 setcont(top
-1, lj_cont_cat
);
269 if (LJ_FR2
) { setnilV(top
); setnilV(top
+2); top
+= 2; }
270 return top
+1; /* Trigger metamethod call. */
272 /* Pick as many strings as possible from the top and concatenate them:
274 ** before: [...][CAT stack ...........................]
275 ** pick str: [...][CAT stack ...] [...... strings ......]
276 ** concat: [...][CAT stack ...] [result]
277 ** next step: [...][CAT stack ............]
280 uint64_t tlen
= tvisstr(o
) ? strV(o
)->len
:
281 tvisbuf(o
) ? sbufxlen(bufV(o
)) : STRFMT_MAXBUF_NUM
;
284 o
--; tlen
+= tvisstr(o
) ? strV(o
)->len
:
285 tvisbuf(o
) ? sbufxlen(bufV(o
)) : STRFMT_MAXBUF_NUM
;
286 } while (--left
> 0 && (tvisstr(o
-1) || tvisnumber(o
-1)));
287 if (tlen
>= LJ_MAX_STR
) lj_err_msg(L
, LJ_ERR_STROV
);
289 lj_buf_more(sb
, (MSize
)tlen
);
290 for (e
= top
, top
= o
; o
<= e
; o
++) {
294 lj_buf_putmem(sb
, strdata(s
), len
);
295 } else if (tvisbuf(o
)) {
296 SBufExt
*sbx
= bufV(o
);
297 lj_buf_putmem(sb
, sbx
->r
, sbufxlen(sbx
));
298 } else if (tvisint(o
)) {
299 lj_strfmt_putint(sb
, intV(o
));
301 lj_strfmt_putfnum(sb
, STRFMT_G14
, numV(o
));
304 setstrV(L
, top
, lj_buf_str(L
, sb
));
307 if (LJ_UNLIKELY(G(L
)->gc
.total
>= G(L
)->gc
.threshold
)) {
308 if (!fromc
) L
->top
= curr_topL(L
);
314 /* Helper for LEN. __len metamethod. */
315 TValue
* LJ_FASTCALL
lj_meta_len(lua_State
*L
, cTValue
*o
)
317 cTValue
*mo
= lj_meta_lookup(L
, o
, MM_len
);
319 if (LJ_52
&& tvistab(o
))
320 tabref(tabV(o
)->metatable
)->nomm
|= (uint8_t)(1u<<MM_len
);
322 lj_err_optype(L
, o
, LJ_ERR_OPLEN
);
325 return mmcall(L
, lj_cont_ra
, mo
, o
, LJ_52
? o
: niltv(L
));
328 /* Helper for equality comparisons. __eq metamethod. */
329 TValue
*lj_meta_equal(lua_State
*L
, GCobj
*o1
, GCobj
*o2
, int ne
)
331 /* Field metatable must be at same offset for GCtab and GCudata! */
332 cTValue
*mo
= lj_meta_fast(L
, tabref(o1
->gch
.metatable
), MM_eq
);
336 if (tabref(o1
->gch
.metatable
) != tabref(o2
->gch
.metatable
)) {
337 cTValue
*mo2
= lj_meta_fast(L
, tabref(o2
->gch
.metatable
), MM_eq
);
338 if (mo2
== NULL
|| !lj_obj_equal(mo
, mo2
))
339 return (TValue
*)(intptr_t)ne
;
342 setcont(top
++, ne
? lj_cont_condf
: lj_cont_condt
);
343 if (LJ_FR2
) setnilV(top
++);
344 copyTV(L
, top
++, mo
);
345 if (LJ_FR2
) setnilV(top
++);
346 it
= ~(uint32_t)o1
->gch
.gct
;
347 setgcV(L
, top
, o1
, it
);
348 setgcV(L
, top
+1, o2
, it
);
349 return top
; /* Trigger metamethod call. */
351 return (TValue
*)(intptr_t)ne
;
355 TValue
* LJ_FASTCALL
lj_meta_equal_cd(lua_State
*L
, BCIns ins
)
357 ASMFunction cont
= (bc_op(ins
) & 1) ? lj_cont_condf
: lj_cont_condt
;
358 int op
= (int)bc_op(ins
) & ~1;
360 cTValue
*mo
, *o2
, *o1
= &L
->base
[bc_a(ins
)];
362 if (op
== BC_ISEQV
) {
363 o2
= &L
->base
[bc_d(ins
)];
364 if (!tviscdata(o1mm
)) o1mm
= o2
;
365 } else if (op
== BC_ISEQS
) {
366 setstrV(L
, &tv
, gco2str(proto_kgc(curr_proto(L
), ~(ptrdiff_t)bc_d(ins
))));
368 } else if (op
== BC_ISEQN
) {
369 o2
= &mref(curr_proto(L
)->k
, cTValue
)[bc_d(ins
)];
371 lj_assertL(op
== BC_ISEQP
, "bad bytecode op %d", op
);
372 setpriV(&tv
, ~bc_d(ins
));
375 mo
= lj_meta_lookup(L
, o1mm
, MM_eq
);
376 if (LJ_LIKELY(!tvisnil(mo
)))
377 return mmcall(L
, cont
, mo
, o1
, o2
);
379 return (TValue
*)(intptr_t)(bc_op(ins
) & 1);
383 /* Helper for ordered comparisons. String compare, __lt/__le metamethods. */
384 TValue
*lj_meta_comp(lua_State
*L
, cTValue
*o1
, cTValue
*o2
, int op
)
386 if (LJ_HASFFI
&& (tviscdata(o1
) || tviscdata(o2
))) {
387 ASMFunction cont
= (op
& 1) ? lj_cont_condf
: lj_cont_condt
;
388 MMS mm
= (op
& 2) ? MM_le
: MM_lt
;
389 cTValue
*mo
= lj_meta_lookup(L
, tviscdata(o1
) ? o1
: o2
, mm
);
390 if (LJ_UNLIKELY(tvisnil(mo
))) goto err
;
391 return mmcall(L
, cont
, mo
, o1
, o2
);
392 } else if (LJ_52
|| itype(o1
) == itype(o2
)) {
393 /* Never called with two numbers. */
394 if (tvisstr(o1
) && tvisstr(o2
)) {
395 int32_t res
= lj_str_cmp(strV(o1
), strV(o2
));
396 return (TValue
*)(intptr_t)(((op
&2) ? res
<= 0 : res
< 0) ^ (op
&1));
400 ASMFunction cont
= (op
& 1) ? lj_cont_condf
: lj_cont_condt
;
401 MMS mm
= (op
& 2) ? MM_le
: MM_lt
;
402 cTValue
*mo
= lj_meta_lookup(L
, o1
, mm
);
404 if (tvisnil(mo
) && tvisnil((mo
= lj_meta_lookup(L
, o2
, mm
))))
406 cTValue
*mo2
= lj_meta_lookup(L
, o2
, mm
);
407 if (tvisnil(mo
) || !lj_obj_equal(mo
, mo2
))
410 if (op
& 2) { /* MM_le not found: retry with MM_lt. */
411 cTValue
*ot
= o1
; o1
= o2
; o2
= ot
; /* Swap operands. */
412 op
^= 3; /* Use LT and flip condition. */
417 return mmcall(L
, cont
, mo
, o1
, o2
);
420 } else if (tvisbool(o1
) && tvisbool(o2
)) {
424 lj_err_comp(L
, o1
, o2
);
429 /* Helper for ISTYPE and ISNUM. Implicit coercion or error. */
430 void lj_meta_istype(lua_State
*L
, BCReg ra
, BCReg tp
)
432 L
->top
= curr_topL(L
);
434 lj_assertL(LJ_DUALNUM
|| tp
!= ~LJ_TNUMX
, "bad type for ISTYPE");
435 if (LJ_DUALNUM
&& tp
== ~LJ_TNUMX
) lj_lib_checkint(L
, ra
);
436 else if (tp
== ~LJ_TNUMX
+1) lj_lib_checknum(L
, ra
);
437 else if (tp
== ~LJ_TSTR
) lj_lib_checkstr(L
, ra
);
438 else lj_err_argtype(L
, ra
, lj_obj_itypename
[tp
]);
441 /* Helper for calls. __call metamethod. */
442 void lj_meta_call(lua_State
*L
, TValue
*func
, TValue
*top
)
444 cTValue
*mo
= lj_meta_lookup(L
, func
, MM_call
);
447 lj_err_optype_call(L
, func
);
448 for (p
= top
; p
> func
+2*LJ_FR2
; p
--) copyTV(L
, p
, p
-1);
449 if (LJ_FR2
) copyTV(L
, func
+2, func
);
453 /* Helper for FORI. Coercion. */
454 void LJ_FASTCALL
lj_meta_for(lua_State
*L
, TValue
*o
)
456 if (!lj_strscan_numberobj(o
)) lj_err_msg(L
, LJ_ERR_FORINIT
);
457 if (!lj_strscan_numberobj(o
+1)) lj_err_msg(L
, LJ_ERR_FORLIM
);
458 if (!lj_strscan_numberobj(o
+2)) lj_err_msg(L
, LJ_ERR_FORSTEP
);
460 /* Ensure all slots are integers or all slots are numbers. */
464 for (i
= 0; i
<= 2; i
++) {
466 k
[i
] = intV(o
+i
); nint
++;
468 k
[i
] = lj_num2int(numV(o
+i
)); nint
+= ((lua_Number
)k
[i
] == numV(o
+i
));
471 if (nint
== 3) { /* Narrow to integers. */
475 } else if (nint
!= 0) { /* Widen to numbers. */
476 if (tvisint(o
)) setnumV(o
, (lua_Number
)intV(o
));
477 if (tvisint(o
+1)) setnumV(o
+1, (lua_Number
)intV(o
+1));
478 if (tvisint(o
+2)) setnumV(o
+2, (lua_Number
)intV(o
+2));