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); }
/* Calculate number of used stack slots in the current frame. */ static BCReg cur_topslot(GCproto *pt, const BCIns *pc, uint32_t nres) { BCIns ins = pc[-1]; if (bc_op(ins) == BC_UCLO) ins = pc[bc_j(ins)]; switch (bc_op(ins)) { case BC_CALLM: case BC_CALLMT: return bc_a(ins) + bc_c(ins) + nres-1+1; case BC_RETM: return bc_a(ins) + bc_d(ins) + nres-1; case BC_TSETM: return bc_a(ins) + nres-1; default: return pt->framesize; } }
/* Unpatch the bytecode modified by a root trace. */ static void trace_unpatch(jit_State *J, GCtrace *T) { BCOp op = bc_op(T->startins); BCIns *pc = mref(T->startpc, BCIns); UNUSED(J); if (op == BC_JMP) return; /* No need to unpatch branches in parent traces (yet). */ switch (bc_op(*pc)) { case BC_JFORL: lua_assert(traceref(J, bc_d(*pc)) == T); *pc = T->startins; pc += bc_j(T->startins); lua_assert(bc_op(*pc) == BC_JFORI); setbc_op(pc, BC_FORI); break; case BC_JITERL: case BC_JLOOP: lua_assert(op == BC_ITERL || op == BC_LOOP || bc_isret(op)); *pc = T->startins; break; case BC_JMP: lua_assert(op == BC_ITERL); pc += bc_j(*pc)+2; if (bc_op(*pc) == BC_JITERL) { lua_assert(traceref(J, bc_d(*pc)) == T); *pc = T->startins; } break; case BC_JFUNCF: lua_assert(op == BC_FUNCF); *pc = T->startins; break; default: /* Already unpatched. */ break; } }
/* Find unused slots with reaching-definitions bytecode data-flow analysis. */ static BCReg snap_usedef(jit_State *J, uint8_t *udf, const BCIns *pc, BCReg maxslot) { BCReg s; GCobj *o; if (maxslot == 0) return 0; #ifdef LUAJIT_USE_VALGRIND /* Avoid errors for harmless reads beyond maxslot. */ memset(udf, 1, SNAP_USEDEF_SLOTS); #else memset(udf, 1, maxslot); #endif /* Treat open upvalues as used. */ o = gcref(J->L->openupval); while (o) { if (uvval(gco2uv(o)) < J->L->base) break; udf[uvval(gco2uv(o)) - J->L->base] = 0; o = gcref(o->gch.nextgc); } #define USE_SLOT(s) udf[(s)] &= ~1 #define DEF_SLOT(s) udf[(s)] *= 3 /* Scan through following bytecode and check for uses/defs. */ lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc); for (;;) { BCIns ins = *pc++; BCOp op = bc_op(ins); switch (bcmode_b(op)) { case BCMvar: USE_SLOT(bc_b(ins)); break; default: break; } switch (bcmode_c(op)) { case BCMvar: USE_SLOT(bc_c(ins)); break; case BCMrbase: lua_assert(op == BC_CAT); for (s = bc_b(ins); s <= bc_c(ins); s++) USE_SLOT(s); for (; s < maxslot; s++) DEF_SLOT(s); break; case BCMjump: handle_jump: { BCReg minslot = bc_a(ins); if (op >= BC_FORI && op <= BC_JFORL) minslot += FORL_EXT; else if (op >= BC_ITERL && op <= BC_JITERL) minslot += bc_b(pc[-2])-1; else if (op == BC_UCLO) { pc += bc_j(ins); break; } for (s = minslot; s < maxslot; s++) DEF_SLOT(s); return minslot < maxslot ? minslot : maxslot; } case BCMlit: if (op == BC_JFORL || op == BC_JITERL || op == BC_JLOOP) { goto handle_jump; } else if (bc_isret(op)) { BCReg top = op == BC_RETM ? maxslot : (bc_a(ins) + bc_d(ins)-1); for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s); for (; s < top; s++) USE_SLOT(s); for (; s < maxslot; s++) DEF_SLOT(s); return 0; } break; case BCMfunc: return maxslot; /* NYI: will abort, anyway. */ default: break; } switch (bcmode_a(op)) { case BCMvar: USE_SLOT(bc_a(ins)); break; case BCMdst: if (!(op == BC_ISTC || op == BC_ISFC)) DEF_SLOT(bc_a(ins)); break; case BCMbase: if (op >= BC_CALLM && op <= BC_VARG) { BCReg top = (op == BC_CALLM || op == BC_CALLMT || bc_c(ins) == 0) ? maxslot : (bc_a(ins) + bc_c(ins)+LJ_FR2); if (LJ_FR2) DEF_SLOT(bc_a(ins)+1); s = bc_a(ins) - ((op == BC_ITERC || op == BC_ITERN) ? 3 : 0); for (; s < top; s++) USE_SLOT(s); for (; s < maxslot; s++) DEF_SLOT(s); if (op == BC_CALLT || op == BC_CALLMT) { for (s = 0; s < bc_a(ins); s++) DEF_SLOT(s); return 0; } } else if (op == BC_KNIL) { for (s = bc_a(ins); s <= bc_d(ins); s++) DEF_SLOT(s); } else if (op == BC_TSETM) { for (s = bc_a(ins)-1; s < maxslot; s++) USE_SLOT(s); } break; default: break; } lua_assert(pc >= proto_bc(J->pt) && pc < proto_bc(J->pt) + J->pt->sizebc); } #undef USE_SLOT #undef DEF_SLOT return 0; /* unreachable */ }
u4 printInstruction_aux(FILE *stream, const BCIns *ins /*in*/, int oneline) { const BCIns *ins0 = ins; u4 j; const BCIns i = *ins; const char *name = ins_name[bc_op(i)]; fprintf(stream, "%p: ", ins); ++ ins; switch(ins_format[bc_op(i)]) { case IFM_R: fprintf(stream, "%s\tr%d\n", name, bc_a(i)); break; case IFM_RR: fprintf(stream, "%s\tr%d, r%d\n", name, bc_a(i), bc_d(i)); break; case IFM_RRR: fprintf(stream, "%s\tr%d, r%d, r%d\n", name, bc_a(i), bc_b(i), bc_c(i)); break; case IFM_RN: fprintf(stream, "%s\tr%d, %d\n", name, bc_a(i), bc_d(i)); break; case IFM_RRN: fprintf(stream, "%s\tr%d, r%d, %d\n", name, bc_a(i), bc_b(i), bc_c(i)); break; case IFM_RS: fprintf(stream, "%s\tr%d, %d\n", name, bc_a(i), bc_sd(i)); break; case IFM_J: fprintf(stream, "%s\t%p\n", name, ins + bc_j(i)); break; case IFM_RRJ: fprintf(stream, "%s\tr%d, r%d, %p\n", name, bc_a(i), bc_d(i), ins + 1 + bc_j(*ins)); ins++; break; case IFM____: switch (bc_op(i)) { case BC_EVAL: { fprintf(stream, "EVAL\tr%d", bc_a(i)); printInlineBitmap(stream, ins); ins++; } break; case BC_CASE: { u2 *tgt = (u2*)ins; u4 ncases = bc_d(i); ins += (ncases + 1) / 2; fprintf(stream, "CASE\tr%d\n", bc_a(i)); if (!oneline) { for (j = 0; j < ncases; j++, tgt++) { fprintf(stream, " %d: %p\n", j + 1, ins + bc_j_from_d(*tgt)); } } } break; case BC_CASE_S: fprintf(stream, "CASE_S\tr%d ...TODO...\n", bc_a(i)); ins += bc_d(i); break; case BC_ALLOC1: fprintf(stream, "ALLOC1\tr%d, r%d, r%d", bc_a(i), bc_b(i), bc_c(i)); printInlineBitmap(stream, ins); ins += 1; break; case BC_ALLOC: { u1 *arg = (u1*)ins; ins += 1 + BC_ROUND(bc_c(i)); fprintf(stream, "ALLOC\tr%d, r%d", bc_a(i), bc_b(i)); for (j = 0; j < bc_c(i); j++, arg++) fprintf(stream, ", r%d", *arg); printInlineBitmap(stream, ins - 1); } break; case BC_ALLOCAP: { u1 *arg = (u1*)ins; ins += 1 + BC_ROUND(bc_c(i) + 1); fprintf(stream, "ALLOCAP\tr%d", bc_a(i)); u1 ptrmask = bc_b(i); fprintf(stream, ", r%d", *arg++); for (j = 1; j < bc_c(i); j++, arg++) { fprintf(stream, ", r%d%c", *arg, ptrmask & 1 ? '*' : ' '); ptrmask >>= 1; } printInlineBitmap(stream, ins - 1); } break; case BC_CALL: { u1 *arg = (u1*)ins; ins += BC_ROUND(bc_c(i)) + 1; fprintf(stream, "%s\tr%d", name, bc_a(i)); char comma = '('; for (j = 0; j < bc_c(i); j++, arg++) { fprintf(stream, "%cr%d", comma, *arg); comma = ','; } fprintf(stream, ") [%x]", bc_b(i)); printInlineBitmap(stream, ins - 1); } break; case BC_CALLT: { int j; u1 bitmask = bc_b(i); fprintf(stream, "CALLT r%d", bc_a(i)); for (j = 0; j < bc_c(i); j++) { fprintf(stream, "%cr%d%c", j == 0 ? '(' : ',', j, bitmask & 1 ? '*' : ' '); bitmask >>= 1; } fprintf(stream, ")\n"); } break; default: fprintf(stream, "%s ...TODO...\n", name); } break; default: fprintf(stderr, "FATAL: Unknown intruction format: %d\n", ins_format[bc_op(i)]); exit(1); } return (u4)(ins - ins0); }