static void jit_profile_callback(lua_State *L2, lua_State *L, int samples, int vmstate) { TValue key; cTValue *tv; setlightudV(&key, (void *)&KEY_PROFILE_FUNC); tv = lj_tab_get(L, tabV(registry(L)), &key); if (tvisfunc(tv)) { char vmst = (char)vmstate; int status; setfuncV(L2, L2->top++, funcV(tv)); setthreadV(L2, L2->top++, L); setintV(L2->top++, samples); setstrV(L2, L2->top++, lj_str_new(L2, &vmst, 1)); status = lua_pcall(L2, 3, 0, 0); /* callback(thread, samples, vmstate) */ if (status) { if (G(L2)->panic) G(L2)->panic(L2); exit(EXIT_FAILURE); } lj_trace_abort(G(L2)); } }
/* 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 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 */ }
/* Array and hash load forwarding. */ static TRef fwd_ahload(jit_State *J, IRRef xref) { IRIns *xr = IR(xref); IRRef lim = xref; /* Search limit. */ IRRef ref; /* Search for conflicting stores. */ ref = J->chain[fins->o+IRDELTA_L2S]; while (ref > xref) { IRIns *store = IR(ref); switch (aa_ahref(J, xr, IR(store->op1))) { case ALIAS_NO: break; /* Continue searching. */ case ALIAS_MAY: lim = ref; goto cselim; /* Limit search for load. */ case ALIAS_MUST: return store->op2; /* Store forwarding. */ } ref = store->prev; } /* No conflicting store (yet): const-fold loads from allocations. */ { IRIns *ir = (xr->o == IR_HREFK || xr->o == IR_AREF) ? IR(xr->op1) : xr; IRRef tab = ir->op1; ir = IR(tab); if (ir->o == IR_TNEW || (ir->o == IR_TDUP && irref_isk(xr->op2))) { /* A NEWREF with a number key may end up pointing to the array part. ** But it's referenced from HSTORE and not found in the ASTORE chain. ** For now simply consider this a conflict without forwarding anything. */ if (xr->o == IR_AREF) { IRRef ref2 = J->chain[IR_NEWREF]; while (ref2 > tab) { IRIns *newref = IR(ref2); if (irt_isnum(IR(newref->op2)->t)) goto cselim; ref2 = newref->prev; } } /* NEWREF inhibits CSE for HREF, and dependent FLOADs from HREFK/AREF. ** But the above search for conflicting stores was limited by xref. ** So continue searching, limited by the TNEW/TDUP. Store forwarding ** is ok, too. A conflict does NOT limit the search for a matching load. */ while (ref > tab) { IRIns *store = IR(ref); switch (aa_ahref(J, xr, IR(store->op1))) { case ALIAS_NO: break; /* Continue searching. */ case ALIAS_MAY: goto cselim; /* Conflicting store. */ case ALIAS_MUST: return store->op2; /* Store forwarding. */ } ref = store->prev; } lua_assert(ir->o != IR_TNEW || irt_isnil(fins->t)); if (irt_ispri(fins->t)) { return TREF_PRI(irt_type(fins->t)); } else if (irt_isnum(fins->t) || (LJ_DUALNUM && irt_isint(fins->t)) || irt_isstr(fins->t)) { TValue keyv; cTValue *tv; IRIns *key = IR(xr->op2); if (key->o == IR_KSLOT) key = IR(key->op1); lj_ir_kvalue(J->L, &keyv, key); tv = lj_tab_get(J->L, ir_ktab(IR(ir->op1)), &keyv); lua_assert(itype2irt(tv) == irt_type(fins->t)); if (irt_isnum(fins->t)) return lj_ir_knum_u64(J, tv->u64); else if (LJ_DUALNUM && irt_isint(fins->t)) return lj_ir_kint(J, intV(tv)); else return lj_ir_kstr(J, strV(tv)); } /* Othwerwise: don't intern as a constant. */ } } cselim: /* Try to find a matching load. Below the conflicting store, if any. */ ref = J->chain[fins->o]; while (ref > lim) { IRIns *load = IR(ref); if (load->op1 == xref) return ref; /* Load forwarding. */ ref = load->prev; } return 0; /* Conflict or no match. */ }