TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins) { ASMFunction cont = (bc_op(ins) & 1) ? lj_cont_condf : lj_cont_condt; int op = (int)bc_op(ins) & ~1; TValue tv; cTValue *mo, *o2, *o1 = &L->base[bc_a(ins)]; cTValue *o1mm = o1; if (op == BC_ISEQV) { o2 = &L->base[bc_d(ins)]; if (!tviscdata(o1mm)) o1mm = o2; } else if (op == BC_ISEQS) { setstrV(L, &tv, gco2str(proto_kgc(curr_proto(L), ~(ptrdiff_t)bc_d(ins)))); o2 = &tv; } else if (op == BC_ISEQN) { o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)]; } else { lua_assert(op == BC_ISEQP); setpriV(&tv, ~bc_d(ins)); o2 = &tv; } mo = lj_meta_lookup(L, o1mm, MM_eq); if (LJ_LIKELY(!tvisnil(mo))) return mmcall(L, cont, mo, o1, o2); else return (TValue *)(intptr_t)(bc_op(ins) & 1); }
/* Helper for LEN. __len metamethod. */ TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o) { cTValue *mo = lj_meta_lookup(L, o, MM_len); if (tvisnil(mo)) { lj_err_optype(L, o, LJ_ERR_OPLEN); return NULL; /* unreachable */ } return mmcall(L, lj_cont_ra, mo, o, niltv(L)); }
/* Helper for LEN. __len metamethod. */ TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o) { cTValue *mo = lj_meta_lookup(L, o, MM_len); if (tvisnil(mo)) { #ifdef LUAJIT_ENABLE_LUA52COMPAT if (tvistab(o)) tabref(tabV(o)->metatable)->nomm |= (uint8_t)(1u<<MM_len); else #endif lj_err_optype(L, o, LJ_ERR_OPLEN); return NULL; } #ifdef LUAJIT_ENABLE_LUA52COMPAT return mmcall(L, lj_cont_ra, mo, o, o); #else return mmcall(L, lj_cont_ra, mo, o, niltv(L)); #endif }
/* Helper for ordered comparisons. String compare, __lt/__le metamethods. */ TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op) { if (LJ_HASFFI && (tviscdata(o1) || tviscdata(o2))) { ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt; MMS mm = (op & 2) ? MM_le : MM_lt; cTValue *mo = lj_meta_lookup(L, tviscdata(o1) ? o1 : o2, mm); if (LJ_UNLIKELY(tvisnil(mo))) goto err; return mmcall(L, cont, mo, o1, o2); } else if (LJ_52 || itype(o1) == itype(o2)) { /* Never called with two numbers. */ if (tvisstr(o1) && tvisstr(o2)) { int32_t res = lj_str_cmp(strV(o1), strV(o2)); return (TValue *)(intptr_t)(((op&2) ? res <= 0 : res < 0) ^ (op&1)); } else { trymt: while (1) { ASMFunction cont = (op & 1) ? lj_cont_condf : lj_cont_condt; MMS mm = (op & 2) ? MM_le : MM_lt; cTValue *mo = lj_meta_lookup(L, o1, mm); #if LJ_52 if (tvisnil(mo) && tvisnil((mo = lj_meta_lookup(L, o2, mm)))) #else cTValue *mo2 = lj_meta_lookup(L, o2, mm); if (tvisnil(mo) || !lj_obj_equal(mo, mo2)) #endif { if (op & 2) { /* MM_le not found: retry with MM_lt. */ cTValue *ot = o1; o1 = o2; o2 = ot; /* Swap operands. */ op ^= 3; /* Use LT and flip condition. */ continue; } goto err; } return mmcall(L, cont, mo, o1, o2); } } } else if (tvisbool(o1) && tvisbool(o2)) { goto trymt; } else { err: lj_err_comp(L, o1, o2); return NULL; } }
/* Helper for LEN. __len metamethod. */ TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o) { cTValue *mo = lj_meta_lookup(L, o, MM_len); if (tvisnil(mo)) { if (LJ_52 && tvistab(o)) tabref(tabV(o)->metatable)->nomm |= (uint8_t)(1u<<MM_len); else lj_err_optype(L, o, LJ_ERR_OPLEN); return NULL; } return mmcall(L, lj_cont_ra, mo, o, LJ_52 ? o : niltv(L)); }
/* Helper for TSET*. __newindex chain and metamethod. */ TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k) { TValue tmp; int loop; for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { cTValue *mo; if (LJ_LIKELY(tvistab(o))) { GCtab *t = tabV(o); cTValue *tv = lj_tab_get(L, t, k); if (LJ_LIKELY(!tvisnil(tv))) { t->nomm = 0; /* Invalidate negative metamethod cache. */ lj_gc_anybarriert(L, t); return (TValue *)tv; } else if (!(mo = lj_meta_fast(L, tabref(t->metatable), MM_newindex))) { t->nomm = 0; /* Invalidate negative metamethod cache. */ lj_gc_anybarriert(L, t); if (tv != niltv(L)) return (TValue *)tv; if (tvisnil(k)) lj_err_msg(L, LJ_ERR_NILIDX); else if (tvisint(k)) { setnumV(&tmp, (lua_Number)intV(k)); k = &tmp; } else if (tvisnum(k) && tvisnan(k)) lj_err_msg(L, LJ_ERR_NANIDX); return lj_tab_newkey(L, t, k); } } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_newindex))) { lj_err_optype(L, o, LJ_ERR_OPINDEX); return NULL; /* unreachable */ } if (tvisfunc(mo)) { L->top = mmcall(L, lj_cont_nop, mo, o, k); /* L->top+2 = v filled in by caller. */ return NULL; /* Trigger metamethod call. */ } copyTV(L, &tmp, mo); o = &tmp; } lj_err_msg(L, LJ_ERR_SETLOOP); return NULL; /* unreachable */ }
/* Helper for arithmetic instructions. Coercion, metamethod. */ TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, BCReg op) { MMS mm = bcmode_mm(op); TValue tempb, tempc; cTValue *b, *c; if ((b = str2num(rb, &tempb)) != NULL && (c = str2num(rc, &tempc)) != NULL) { /* Try coercion first. */ setnumV(ra, lj_vm_foldarith(numV(b), numV(c), (int)mm-MM_add)); return NULL; } else { cTValue *mo = lj_meta_lookup(L, rb, mm); if (tvisnil(mo)) { mo = lj_meta_lookup(L, rc, mm); if (tvisnil(mo)) { if (str2num(rb, &tempb) == NULL) rc = rb; lj_err_optype(L, rc, LJ_ERR_OPARITH); return NULL; /* unreachable */ } } return mmcall(L, lj_cont_ra, mo, rb, rc); } }
/* Helper for TGET*. __index chain and metamethod. */ cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k) { int loop; for (loop = 0; loop < LJ_MAX_IDXCHAIN; loop++) { cTValue *mo; if (LJ_LIKELY(tvistab(o))) { GCtab *t = tabV(o); cTValue *tv = lj_tab_get(L, t, k); if (!tvisnil(tv) || !(mo = lj_meta_fast(L, tabref(t->metatable), MM_index))) return tv; } else if (tvisnil(mo = lj_meta_lookup(L, o, MM_index))) { lj_err_optype(L, o, LJ_ERR_OPINDEX); return NULL; /* unreachable */ } if (tvisfunc(mo)) { L->top = mmcall(L, lj_cont_ra, mo, o, k); return NULL; /* Trigger metamethod call. */ } o = mo; } lj_err_msg(L, LJ_ERR_GETLOOP); return NULL; /* unreachable */ }