From 87b560b3e18dc39934f7e49810f418a934036a61 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Wed, 8 May 2013 10:37:52 +0200 Subject: [PATCH] Compile string.find() for fixed string searches (no patterns). --- src/lib_string.c | 2 +- src/lj_ffrecord.c | 108 +++++++++++++++++++++++++++++++++++++--------- src/lj_ircall.h | 1 + 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/src/lib_string.c b/src/lib_string.c index ac21dda4..2c86daa4 100644 --- a/src/lib_string.c +++ b/src/lib_string.c @@ -501,7 +501,7 @@ static int str_find_aux(lua_State *L, int find) return 1; } -LJLIB_CF(string_find) +LJLIB_CF(string_find) LJLIB_REC(.) { return str_find_aux(L, 1); } diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index 5f69ea14..39e80842 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c @@ -646,6 +646,32 @@ static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) /* -- String library fast functions --------------------------------------- */ +/* Specialize to relative starting position for string. */ +static TRef recff_string_start(jit_State *J, GCstr *s, int32_t *st, TRef tr, + TRef trlen, TRef tr0) +{ + int32_t start = *st; + if (start < 0) { + emitir(IRTGI(IR_LT), tr, tr0); + tr = emitir(IRTI(IR_ADD), trlen, tr); + start = start + (int32_t)s->len; + emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), tr, tr0); + if (start < 0) { + tr = tr0; + start = 0; + } + } else if (start == 0) { + emitir(IRTGI(IR_EQ), tr, tr0); + tr = tr0; + } else { + tr = emitir(IRTI(IR_ADD), tr, lj_ir_kint(J, -1)); + emitir(IRTGI(IR_GE), tr, tr0); + start--; + } + *st = start; + return tr; +} + /* Handle string.byte (rd->data = 0) and string.sub (rd->data = 1). */ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) { @@ -691,29 +717,11 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) } else if ((MSize)end <= str->len) { emitir(IRTGI(IR_ULE), trend, trlen); } else { - emitir(IRTGI(IR_GT), trend, trlen); + emitir(IRTGI(IR_UGT), trend, trlen); end = (int32_t)str->len; trend = trlen; } - if (start < 0) { - emitir(IRTGI(IR_LT), trstart, tr0); - trstart = emitir(IRTI(IR_ADD), trlen, trstart); - start = start+(int32_t)str->len; - emitir(start < 0 ? IRTGI(IR_LT) : IRTGI(IR_GE), trstart, tr0); - if (start < 0) { - trstart = tr0; - start = 0; - } - } else { - if (start == 0) { - emitir(IRTGI(IR_EQ), trstart, tr0); - trstart = tr0; - } else { - trstart = emitir(IRTI(IR_ADD), trstart, lj_ir_kint(J, -1)); - emitir(IRTGI(IR_GE), trstart, tr0); - start--; - } - } + trstart = recff_string_start(J, str, &start, trstart, trlen, tr0); if (rd->data) { /* Return string.sub result. */ if (end - start >= 0) { /* Also handle empty range here, to avoid extra traces. */ @@ -723,7 +731,7 @@ static void LJ_FASTCALL recff_string_range(jit_State *J, RecordFFData *rd) J->base[0] = emitir(IRT(IR_SNEW, IRT_STR), trptr, trslen); } else { /* Range underflow: return empty string. */ emitir(IRTGI(IR_LT), trend, trstart); - J->base[0] = lj_ir_kstr(J, lj_str_new(J->L, strdata(str), 0)); + J->base[0] = lj_ir_kstr(J, &J2G(J)->strempty); } } else { /* Return string.byte result(s). */ ptrdiff_t i, len = end - start; @@ -802,6 +810,64 @@ static void LJ_FASTCALL recff_string_op(jit_State *J, RecordFFData *rd) J->base[0] = emitir(IRT(IR_BUFSTR, IRT_STR), tr, hdr); } +static void LJ_FASTCALL recff_string_find(jit_State *J, RecordFFData *rd) +{ + TRef trstr = lj_ir_tostr(J, J->base[0]); + TRef trpat = lj_ir_tostr(J, J->base[1]); + TRef trlen = emitir(IRTI(IR_FLOAD), trstr, IRFL_STR_LEN); + TRef tr0 = lj_ir_kint(J, 0); + TRef trstart; + GCstr *str = argv2str(J, &rd->argv[0]); + GCstr *pat = argv2str(J, &rd->argv[1]); + int32_t start; + J->needsnap = 1; + if (tref_isnil(J->base[2])) { + trstart = lj_ir_kint(J, 1); + start = 1; + } else { + trstart = lj_opt_narrow_toint(J, J->base[2]); + start = argv2int(J, &rd->argv[2]); + } + trstart = recff_string_start(J, str, &start, trstart, trlen, tr0); + if ((MSize)start <= str->len) { + emitir(IRTGI(IR_ULE), trstart, trlen); + } else { + emitir(IRTGI(IR_UGT), trstart, trlen); +#if LJ_52 + J->base[0] = TREF_NIL; + return; +#else + trstart = trlen; + start = str->len; +#endif + } + /* Fixed arg or no pattern matching chars? (Specialized to pattern string.) */ + if ((J->base[2] && tref_istruecond(J->base[3])) || + (emitir(IRTG(IR_EQ, IRT_STR), trpat, lj_ir_kstr(J, pat)), + !lj_str_haspattern(pat))) { /* Search for fixed string. */ + TRef trsptr = emitir(IRT(IR_STRREF, IRT_P32), trstr, trstart); + TRef trpptr = emitir(IRT(IR_STRREF, IRT_P32), trpat, tr0); + TRef trslen = emitir(IRTI(IR_SUB), trlen, trstart); + TRef trplen = emitir(IRTI(IR_FLOAD), trpat, IRFL_STR_LEN); + TRef tr = lj_ir_call(J, IRCALL_lj_str_find, trsptr, trpptr, trslen, trplen); + TRef trp0 = lj_ir_kkptr(J, NULL); + if (lj_str_find(strdata(str)+(MSize)start, strdata(pat), + str->len-(MSize)start, pat->len)) { + TRef pos; + emitir(IRTG(IR_NE, IRT_P32), tr, trp0); + pos = emitir(IRTI(IR_SUB), tr, emitir(IRT(IR_STRREF, IRT_P32), trstr, tr0)); + J->base[0] = emitir(IRTI(IR_ADD), pos, lj_ir_kint(J, 1)); + J->base[1] = emitir(IRTI(IR_ADD), pos, trplen); + rd->nres = 2; + } else { + emitir(IRTG(IR_EQ, IRT_P32), tr, trp0); + J->base[0] = TREF_NIL; + } + } else { /* Search for pattern. */ + recff_nyiu(J); + } +} + /* -- Table library fast functions ---------------------------------------- */ static void LJ_FASTCALL recff_table_insert(jit_State *J, RecordFFData *rd) diff --git a/src/lj_ircall.h b/src/lj_ircall.h index 8713e3f0..03563cd6 100644 --- a/src/lj_ircall.h +++ b/src/lj_ircall.h @@ -101,6 +101,7 @@ typedef struct CCallInfo { /* Function definitions for CALL* instructions. */ #define IRCALLDEF(_) \ _(ANY, lj_str_cmp, 2, FN, INT, CCI_NOFPRCLOBBER) \ + _(ANY, lj_str_find, 4, N, P32, 0) \ _(ANY, lj_str_new, 3, S, STR, CCI_L) \ _(ANY, lj_strscan_num, 2, FN, INT, 0) \ _(ANY, lj_str_fromint, 2, FN, STR, CCI_L) \