Compile __concat metamethod.

This commit is contained in:
Mike Pall 2013-04-28 01:51:41 +02:00
parent 8b3a320089
commit 4ac25a9132

View File

@ -678,6 +678,8 @@ static int check_downrec_unroll(jit_State *J, GCproto *pt)
return 0; return 0;
} }
static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot);
/* Record return. */ /* Record return. */
void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults) void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
{ {
@ -770,7 +772,24 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
} else if (cont == lj_cont_nop) { } else if (cont == lj_cont_nop) {
/* Nothing to do here. */ /* Nothing to do here. */
} else if (cont == lj_cont_cat) { } else if (cont == lj_cont_cat) {
lua_assert(0); BCReg bslot = bc_b(*(frame_contpc(frame)-1));
TRef tr = gotresults ? J->base[cbase+rbase] : TREF_NIL;
if (bslot != cbase-2) { /* Concatenate the remainder. */
TValue *b = J->L->base, save; /* Simulate lower frame and result. */
J->base[cbase-2] = tr;
copyTV(J->L, &save, b-2);
if (gotresults) copyTV(J->L, b-2, b+rbase); else setnilV(b-2);
J->L->base = b - cbase;
tr = rec_cat(J, bslot, cbase-2);
b = J->L->base + cbase; /* Undo. */
J->L->base = b;
copyTV(J->L, b-2, &save);
}
if (tr) { /* Store final result. */
BCReg dst = bc_a(*(frame_contpc(frame)-1));
J->base[dst] = tr;
if (dst >= J->maxslot) J->maxslot = dst+1;
} /* Otherwise continue with another __concat call. */
} else { } else {
/* Result type already specialized. */ /* Result type already specialized. */
lua_assert(cont == lj_cont_condf || cont == lj_cont_condt); lua_assert(cont == lj_cont_condf || cont == lj_cont_condt);
@ -786,13 +805,11 @@ void lj_record_ret(jit_State *J, BCReg rbase, ptrdiff_t gotresults)
/* Prepare to record call to metamethod. */ /* Prepare to record call to metamethod. */
static BCReg rec_mm_prep(jit_State *J, ASMFunction cont) static BCReg rec_mm_prep(jit_State *J, ASMFunction cont)
{ {
BCReg s, top = curr_proto(J->L)->framesize; BCReg s, top = cont == lj_cont_cat ? J->maxslot : curr_proto(J->L)->framesize;
TRef trcont;
setcont(&J->L->base[top], cont);
#if LJ_64 #if LJ_64
trcont = lj_ir_kptr(J, (void *)((int64_t)cont - (int64_t)lj_vm_asm_begin)); TRef trcont = lj_ir_kptr(J, (void *)((int64_t)cont-(int64_t)lj_vm_asm_begin));
#else #else
trcont = lj_ir_kptr(J, (void *)cont); TRef trcont = lj_ir_kptr(J, (void *)cont);
#endif #endif
J->base[top] = trcont | TREF_CONT; J->base[top] = trcont | TREF_CONT;
J->framedepth++; J->framedepth++;
@ -873,7 +890,7 @@ nocheck:
static TRef rec_mm_arith(jit_State *J, RecordIndex *ix, MMS mm) static TRef rec_mm_arith(jit_State *J, RecordIndex *ix, MMS mm)
{ {
/* Set up metamethod call first to save ix->tab and ix->tabv. */ /* Set up metamethod call first to save ix->tab and ix->tabv. */
BCReg func = rec_mm_prep(J, lj_cont_ra); BCReg func = rec_mm_prep(J, mm == MM_concat ? lj_cont_cat : lj_cont_ra);
TRef *base = J->base + func; TRef *base = J->base + func;
TValue *basev = J->L->base + func; TValue *basev = J->L->base + func;
base[1] = ix->tab; base[2] = ix->key; base[1] = ix->tab; base[2] = ix->key;
@ -1604,10 +1621,15 @@ static TRef rec_tnew(jit_State *J, uint32_t ah)
static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot) static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
{ {
TRef *top = &J->base[topslot], tr = *top; TRef *top = &J->base[topslot];
TValue savetv[5];
BCReg s;
RecordIndex ix;
lua_assert(baseslot < topslot); lua_assert(baseslot < topslot);
if (tref_isnumber_str(tr) && tref_isnumber_str(*(top-1))) { for (s = baseslot; s <= topslot; s++)
TRef hdr, *trp, *xbase, *base = &J->base[baseslot]; (void)getslot(J, s); /* Ensure all arguments have a reference. */
if (tref_isnumber_str(top[0]) && tref_isnumber_str(top[-1])) {
TRef tr, hdr, *trp, *xbase, *base = &J->base[baseslot];
/* First convert numbers to strings. */ /* First convert numbers to strings. */
for (trp = top; trp >= base; trp--) { for (trp = top; trp >= base; trp--) {
if (tref_isnumber(*trp)) if (tref_isnumber(*trp))
@ -1624,11 +1646,23 @@ static TRef rec_cat(jit_State *J, BCReg baseslot, BCReg topslot)
} while (trp <= top); } while (trp <= top);
tr = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); tr = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr);
J->maxslot = (BCReg)(xbase - J->base); J->maxslot = (BCReg)(xbase - J->base);
if (xbase == base) return tr; if (xbase == base) return tr; /* Return simple concatenation result. */
/* Pass partial result. */
topslot = J->maxslot--;
*xbase = tr;
top = xbase;
setstrV(J->L, &ix.keyv, &J2G(J)->strempty); /* Simulate string result. */
} else {
J->maxslot = topslot-1;
copyTV(J->L, &ix.keyv, &J->L->base[topslot]);
} }
setintV(&J->errinfo, BC_CAT); copyTV(J->L, &ix.tabv, &J->L->base[topslot-1]);
lj_trace_err_info(J, LJ_TRERR_NYIBC); /* __concat metamethod. */ ix.tab = top[-1];
return 0; ix.key = top[0];
memcpy(savetv, &J->L->base[topslot-1], sizeof(savetv)); /* Save slots. */
rec_mm_arith(J, &ix, MM_concat); /* Call __concat metamethod. */
memcpy(&J->L->base[topslot-1], savetv, sizeof(savetv)); /* Restore slots. */
return 0; /* No result yet. */
} }
/* -- Record bytecode ops ------------------------------------------------- */ /* -- Record bytecode ops ------------------------------------------------- */