Mercurial
comparison third_party/luajit/src/lj_meta.c @ 186:8cf4ec5e2191 hg-web
Fixed merge conflict.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:38:59 -0800 |
| parents | 94705b5986b3 |
| children |
comparison
equal
deleted
inserted
replaced
| 176:fed99fc04e12 | 186:8cf4ec5e2191 |
|---|---|
| 1 /* | |
| 2 ** Metamethod handling. | |
| 3 ** Copyright (C) 2005-2023 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_buf.h" | |
| 16 #include "lj_str.h" | |
| 17 #include "lj_tab.h" | |
| 18 #include "lj_meta.h" | |
| 19 #include "lj_frame.h" | |
| 20 #include "lj_bc.h" | |
| 21 #include "lj_vm.h" | |
| 22 #include "lj_strscan.h" | |
| 23 #include "lj_strfmt.h" | |
| 24 #include "lj_lib.h" | |
| 25 | |
| 26 /* -- Metamethod handling ------------------------------------------------- */ | |
| 27 | |
| 28 /* String interning of metamethod names for fast indexing. */ | |
| 29 void lj_meta_init(lua_State *L) | |
| 30 { | |
| 31 #define MMNAME(name) "__" #name | |
| 32 const char *metanames = MMDEF(MMNAME); | |
| 33 #undef MMNAME | |
| 34 global_State *g = G(L); | |
| 35 const char *p, *q; | |
| 36 uint32_t mm; | |
| 37 for (mm = 0, p = metanames; *p; mm++, p = q) { | |
| 38 GCstr *s; | |
| 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)); | |
| 43 } | |
| 44 } | |
| 45 | |
| 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) | |
| 48 { | |
| 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. */ | |
| 53 return NULL; | |
| 54 } | |
| 55 return mo; | |
| 56 } | |
| 57 | |
| 58 /* Lookup metamethod for object. */ | |
| 59 cTValue *lj_meta_lookup(lua_State *L, cTValue *o, MMS mm) | |
| 60 { | |
| 61 GCtab *mt; | |
| 62 if (tvistab(o)) | |
| 63 mt = tabref(tabV(o)->metatable); | |
| 64 else if (tvisudata(o)) | |
| 65 mt = tabref(udataV(o)->metatable); | |
| 66 else | |
| 67 mt = tabref(basemt_obj(G(L), o)); | |
| 68 if (mt) { | |
| 69 cTValue *mo = lj_tab_getstr(mt, mmname_str(G(L), mm)); | |
| 70 if (mo) | |
| 71 return mo; | |
| 72 } | |
| 73 return niltv(L); | |
| 74 } | |
| 75 | |
| 76 #if LJ_HASFFI | |
| 77 /* Tailcall from C function. */ | |
| 78 int lj_meta_tailcall(lua_State *L, cTValue *tv) | |
| 79 { | |
| 80 TValue *base = L->base; | |
| 81 TValue *top = L->top; | |
| 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. */ | |
| 84 if (LJ_FR2) | |
| 85 (top++)->u64 = LJ_CONT_TAILCALL; | |
| 86 else | |
| 87 top->u32.lo = LJ_CONT_TAILCALL; | |
| 88 setframe_pc(top++, pc); | |
| 89 setframe_gc(top, obj2gco(L), LJ_TTHREAD); /* Dummy frame object. */ | |
| 90 if (LJ_FR2) top++; | |
| 91 setframe_ftsz(top, ((char *)(top+1) - (char *)base) + FRAME_CONT); | |
| 92 L->base = L->top = top+1; | |
| 93 /* | |
| 94 ** before: [old_mo|PC] [... ...] | |
| 95 ** ^base ^top | |
| 96 ** after: [new_mo|itype] [... ...] [NULL|PC] [dummy|delta] | |
| 97 ** ^base/top | |
| 98 ** tailcall: [new_mo|PC] [... ...] | |
| 99 ** ^base ^top | |
| 100 */ | |
| 101 return 0; | |
| 102 } | |
| 103 #endif | |
| 104 | |
| 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) | |
| 108 { | |
| 109 /* | |
| 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 ...] | |
| 120 */ | |
| 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++); | |
| 127 copyTV(L, top, a); | |
| 128 copyTV(L, top+1, b); | |
| 129 return top; /* Return new base. */ | |
| 130 } | |
| 131 | |
| 132 /* -- C helpers for some instructions, called from assembler VM ----------- */ | |
| 133 | |
| 134 /* Helper for TGET*. __index chain and metamethod. */ | |
| 135 cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k) | |
| 136 { | |
| 137 int loop; | |
| 138 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { | |
| 139 cTValue *mo; | |
| 140 if (LJ_LIKELY(tvistab(o))) { | |
| 141 GCtab *t = tabV(o); | |
| 142 cTValue *tv = lj_tab_get(L, t, k); | |
| 143 if (!tvisnil(tv) || | |
| 144 !(mo = lj_meta_fast(L, tabref(t->metatable), MM_index))) | |
| 145 return tv; | |
| 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 */ | |
| 149 } | |
| 150 if (tvisfunc(mo)) { | |
| 151 L->top = mmcall(L, lj_cont_ra, mo, o, k); | |
| 152 return NULL; /* Trigger metamethod call. */ | |
| 153 } | |
| 154 o = mo; | |
| 155 } | |
| 156 lj_err_msg(L, LJ_ERR_GETLOOP); | |
| 157 return NULL; /* unreachable */ | |
| 158 } | |
| 159 | |
| 160 /* Helper for TSET*. __newindex chain and metamethod. */ | |
| 161 TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k) | |
| 162 { | |
| 163 TValue tmp; | |
| 164 int loop; | |
| 165 for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { | |
| 166 cTValue *mo; | |
| 167 if (LJ_LIKELY(tvistab(o))) { | |
| 168 GCtab *t = tabV(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); | |
| 173 return (TValue *)tv; | |
| 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); | |
| 177 if (tv != niltv(L)) | |
| 178 return (TValue *)tv; | |
| 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); | |
| 183 } | |
| 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 */ | |
| 187 } | |
| 188 if (tvisfunc(mo)) { | |
| 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. */ | |
| 192 } | |
| 193 copyTV(L, &tmp, mo); | |
| 194 o = &tmp; | |
| 195 } | |
| 196 lj_err_msg(L, LJ_ERR_SETLOOP); | |
| 197 return NULL; /* unreachable */ | |
| 198 } | |
| 199 | |
| 200 static cTValue *str2num(cTValue *o, TValue *n) | |
| 201 { | |
| 202 if (tvisnum(o)) | |
| 203 return o; | |
| 204 else if (tvisint(o)) | |
| 205 return (setnumV(n, (lua_Number)intV(o)), n); | |
| 206 else if (tvisstr(o) && lj_strscan_num(strV(o), n)) | |
| 207 return n; | |
| 208 else | |
| 209 return NULL; | |
| 210 } | |
| 211 | |
| 212 /* Helper for arithmetic instructions. Coercion, metamethod. */ | |
| 213 TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, | |
| 214 BCReg op) | |
| 215 { | |
| 216 MMS mm = bcmode_mm(op); | |
| 217 TValue tempb, tempc; | |
| 218 cTValue *b, *c; | |
| 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)); | |
| 222 return NULL; | |
| 223 } else { | |
| 224 cTValue *mo = lj_meta_lookup(L, rb, mm); | |
| 225 if (tvisnil(mo)) { | |
| 226 mo = lj_meta_lookup(L, rc, mm); | |
| 227 if (tvisnil(mo)) { | |
| 228 if (str2num(rb, &tempb) == NULL) rc = rb; | |
| 229 lj_err_optype(L, rc, LJ_ERR_OPARITH); | |
| 230 return NULL; /* unreachable */ | |
| 231 } | |
| 232 } | |
| 233 return mmcall(L, lj_cont_ra, mo, rb, rc); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ | |
| 238 TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | |
| 239 { | |
| 240 int fromc = 0; | |
| 241 if (left < 0) { left = -left; fromc = 1; } | |
| 242 do { | |
| 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); | |
| 246 if (tvisnil(mo)) { | |
| 247 mo = lj_meta_lookup(L, top, MM_concat); | |
| 248 if (tvisnil(mo)) { | |
| 249 if (tvisstr(top-1) || tvisnumber(top-1)) top++; | |
| 250 lj_err_optype(L, top-1, LJ_ERR_OPCAT); | |
| 251 return NULL; /* unreachable */ | |
| 252 } | |
| 253 } | |
| 254 /* One of the top two elements is not a string, call __cat metamethod: | |
| 255 ** | |
| 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 .............] | |
| 264 */ | |
| 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. */ | |
| 271 } else { | |
| 272 /* Pick as many strings as possible from the top and concatenate them: | |
| 273 ** | |
| 274 ** before: [...][CAT stack ...........................] | |
| 275 ** pick str: [...][CAT stack ...] [...... strings ......] | |
| 276 ** concat: [...][CAT stack ...] [result] | |
| 277 ** next step: [...][CAT stack ............] | |
| 278 */ | |
| 279 TValue *e, *o = top; | |
| 280 uint64_t tlen = tvisstr(o) ? strV(o)->len : | |
| 281 tvisbuf(o) ? sbufxlen(bufV(o)) : STRFMT_MAXBUF_NUM; | |
| 282 SBuf *sb; | |
| 283 do { | |
| 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); | |
| 288 sb = lj_buf_tmp_(L); | |
| 289 lj_buf_more(sb, (MSize)tlen); | |
| 290 for (e = top, top = o; o <= e; o++) { | |
| 291 if (tvisstr(o)) { | |
| 292 GCstr *s = strV(o); | |
| 293 MSize len = s->len; | |
| 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)); | |
| 300 } else { | |
| 301 lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)); | |
| 302 } | |
| 303 } | |
| 304 setstrV(L, top, lj_buf_str(L, sb)); | |
| 305 } | |
| 306 } while (left >= 1); | |
| 307 if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { | |
| 308 if (!fromc) L->top = curr_topL(L); | |
| 309 lj_gc_step(L); | |
| 310 } | |
| 311 return NULL; | |
| 312 } | |
| 313 | |
| 314 /* Helper for LEN. __len metamethod. */ | |
| 315 TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o) | |
| 316 { | |
| 317 cTValue *mo = lj_meta_lookup(L, o, MM_len); | |
| 318 if (tvisnil(mo)) { | |
| 319 if (LJ_52 && tvistab(o)) | |
| 320 tabref(tabV(o)->metatable)->nomm |= (uint8_t)(1u<<MM_len); | |
| 321 else | |
| 322 lj_err_optype(L, o, LJ_ERR_OPLEN); | |
| 323 return NULL; | |
| 324 } | |
| 325 return mmcall(L, lj_cont_ra, mo, o, LJ_52 ? o : niltv(L)); | |
| 326 } | |
| 327 | |
| 328 /* Helper for equality comparisons. __eq metamethod. */ | |
| 329 TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne) | |
| 330 { | |
| 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); | |
| 333 if (mo) { | |
| 334 TValue *top; | |
| 335 uint32_t it; | |
| 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; | |
| 340 } | |
| 341 top = curr_top(L); | |
| 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. */ | |
| 350 } | |
| 351 return (TValue *)(intptr_t)ne; | |
| 352 } | |
| 353 | |
| 354 #if LJ_HASFFI | |
| 355 TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins) | |
| 356 { | |
| 357 ASMFunction cont = (bc_op(ins) & 1) ? lj_cont_condf : lj_cont_condt; | |
| 358 int op = (int)bc_op(ins) & ~1; | |
| 359 TValue tv; | |
| 360 cTValue *mo, *o2, *o1 = &L->base[bc_a(ins)]; | |
| 361 cTValue *o1mm = o1; | |
| 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)))); | |
| 367 o2 = &tv; | |
| 368 } else if (op == BC_ISEQN) { | |
| 369 o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)]; | |
| 370 } else { | |
| 371 lj_assertL(op == BC_ISEQP, "bad bytecode op %d", op); | |
| 372 setpriV(&tv, ~bc_d(ins)); | |
| 373 o2 = &tv; | |
| 374 } | |
| 375 mo = lj_meta_lookup(L, o1mm, MM_eq); | |
| 376 if (LJ_LIKELY(!tvisnil(mo))) | |
| 377 return mmcall(L, cont, mo, o1, o2); | |
| 378 else | |
| 379 return (TValue *)(intptr_t)(bc_op(ins) & 1); | |
| 380 } | |
| 381 #endif | |
| 382 | |
| 383 /* Helper for ordered comparisons. String compare, __lt/__le metamethods. */ | |
| 384 TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op) | |
| 385 { | |
| 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)); | |
| 397 } else { | |
| 398 trymt: | |
| 399 while (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); | |
| 403 #if LJ_52 | |
| 404 if (tvisnil(mo) && tvisnil((mo = lj_meta_lookup(L, o2, mm)))) | |
| 405 #else | |
| 406 cTValue *mo2 = lj_meta_lookup(L, o2, mm); | |
| 407 if (tvisnil(mo) || !lj_obj_equal(mo, mo2)) | |
| 408 #endif | |
| 409 { | |
| 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. */ | |
| 413 continue; | |
| 414 } | |
| 415 goto err; | |
| 416 } | |
| 417 return mmcall(L, cont, mo, o1, o2); | |
| 418 } | |
| 419 } | |
| 420 } else if (tvisbool(o1) && tvisbool(o2)) { | |
| 421 goto trymt; | |
| 422 } else { | |
| 423 err: | |
| 424 lj_err_comp(L, o1, o2); | |
| 425 return NULL; | |
| 426 } | |
| 427 } | |
| 428 | |
| 429 /* Helper for ISTYPE and ISNUM. Implicit coercion or error. */ | |
| 430 void lj_meta_istype(lua_State *L, BCReg ra, BCReg tp) | |
| 431 { | |
| 432 L->top = curr_topL(L); | |
| 433 ra++; tp--; | |
| 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]); | |
| 439 } | |
| 440 | |
| 441 /* Helper for calls. __call metamethod. */ | |
| 442 void lj_meta_call(lua_State *L, TValue *func, TValue *top) | |
| 443 { | |
| 444 cTValue *mo = lj_meta_lookup(L, func, MM_call); | |
| 445 TValue *p; | |
| 446 if (!tvisfunc(mo)) | |
| 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); | |
| 450 copyTV(L, func, mo); | |
| 451 } | |
| 452 | |
| 453 /* Helper for FORI. Coercion. */ | |
| 454 void LJ_FASTCALL lj_meta_for(lua_State *L, TValue *o) | |
| 455 { | |
| 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); | |
| 459 if (LJ_DUALNUM) { | |
| 460 /* Ensure all slots are integers or all slots are numbers. */ | |
| 461 int32_t k[3]; | |
| 462 int nint = 0; | |
| 463 ptrdiff_t i; | |
| 464 for (i = 0; i <= 2; i++) { | |
| 465 if (tvisint(o+i)) { | |
| 466 k[i] = intV(o+i); nint++; | |
| 467 } else { | |
| 468 k[i] = lj_num2int(numV(o+i)); nint += ((lua_Number)k[i] == numV(o+i)); | |
| 469 } | |
| 470 } | |
| 471 if (nint == 3) { /* Narrow to integers. */ | |
| 472 setintV(o, k[0]); | |
| 473 setintV(o+1, k[1]); | |
| 474 setintV(o+2, k[2]); | |
| 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)); | |
| 479 } | |
| 480 } | |
| 481 } | |
| 482 |