mirror of
https://github.com/LuaJIT/LuaJIT.git
synced 2025-02-12 09:24:07 +00:00
Refactor string.rep().
This commit is contained in:
parent
a98e6a70c1
commit
9b8db403f2
@ -85,53 +85,23 @@ LJLIB_ASM(string_sub) LJLIB_REC(string_range 1)
|
||||
return FFH_RETRY;
|
||||
}
|
||||
|
||||
LJLIB_ASM(string_rep)
|
||||
LJLIB_CF(string_rep)
|
||||
{
|
||||
GCstr *s = lj_lib_checkstr(L, 1);
|
||||
int32_t k = lj_lib_checkint(L, 2);
|
||||
int32_t rep = lj_lib_checkint(L, 2);
|
||||
GCstr *sep = lj_lib_optstr(L, 3);
|
||||
int32_t len = (int32_t)s->len;
|
||||
global_State *g = G(L);
|
||||
int64_t tlen;
|
||||
if (k <= 0) {
|
||||
empty:
|
||||
setstrV(L, L->base-1, &g->strempty);
|
||||
return FFH_RES(1);
|
||||
SBuf *sb = lj_buf_tmp_(L);
|
||||
if (sep && rep > 1) {
|
||||
GCstr *s2 = lj_buf_cat2str(L, sep, s);
|
||||
lj_buf_reset(sb);
|
||||
lj_buf_putstr(sb, s);
|
||||
s = s2;
|
||||
rep--;
|
||||
}
|
||||
if (sep) {
|
||||
tlen = (int64_t)len + sep->len;
|
||||
if (tlen > LJ_MAX_STR)
|
||||
lj_err_caller(L, LJ_ERR_STROV);
|
||||
tlen *= k;
|
||||
if (tlen > LJ_MAX_STR)
|
||||
lj_err_caller(L, LJ_ERR_STROV);
|
||||
} else {
|
||||
tlen = (int64_t)k * len;
|
||||
if (tlen > LJ_MAX_STR)
|
||||
lj_err_caller(L, LJ_ERR_STROV);
|
||||
}
|
||||
if (tlen == 0) {
|
||||
goto empty;
|
||||
} else {
|
||||
char *buf = lj_buf_tmp(L, (MSize)tlen), *p = buf;
|
||||
const char *src = strdata(s);
|
||||
if (sep) {
|
||||
tlen -= sep->len; /* Ignore trailing separator. */
|
||||
if (k > 1) { /* Paste one string and one separator. */
|
||||
int32_t i;
|
||||
i = 0; while (i < len) *p++ = src[i++];
|
||||
src = strdata(sep); len = sep->len;
|
||||
i = 0; while (i < len) *p++ = src[i++];
|
||||
src = buf; len += s->len; k--; /* Now copy that k-1 times. */
|
||||
}
|
||||
}
|
||||
do {
|
||||
int32_t i = 0;
|
||||
do { *p++ = src[i++]; } while (i < len);
|
||||
} while (--k > 0);
|
||||
setstrV(L, L->base-1, lj_str_new(L, buf, (size_t)tlen));
|
||||
}
|
||||
return FFH_RES(1);
|
||||
sb = lj_buf_putstr_rep(sb, s, rep);
|
||||
setstrV(L, L->top-1, lj_buf_str(L, sb));
|
||||
lj_gc_check(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJLIB_ASM(string_reverse) LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse)
|
||||
|
24
src/lj_buf.c
24
src/lj_buf.c
@ -144,6 +144,30 @@ SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s)
|
||||
return sb;
|
||||
}
|
||||
|
||||
SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep)
|
||||
{
|
||||
MSize len = s->len;
|
||||
if (rep > 0 && len) {
|
||||
uint64_t tlen = (uint64_t)rep * len;
|
||||
char *p;
|
||||
if (LJ_UNLIKELY(tlen > LJ_MAX_STR))
|
||||
lj_err_mem(sbufL(sb));
|
||||
p = lj_buf_more(sb, (MSize)tlen);
|
||||
if (len == 1) { /* Optimize a common case. */
|
||||
uint32_t c = strdata(s)[0];
|
||||
do { *p++ = c; } while (--rep > 0);
|
||||
} else {
|
||||
const char *e = strdata(s) + len;
|
||||
do {
|
||||
const char *q = strdata(s);
|
||||
do { *p++ = *q++; } while (q < e);
|
||||
} while (--rep > 0);
|
||||
}
|
||||
setsbufP(sb, p);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb)
|
||||
{
|
||||
return lj_str_new(sbufL(sb), sbufB(sb), sbuflen(sb));
|
||||
|
@ -35,6 +35,7 @@ LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putnum(SBuf *sb, cTValue *o);
|
||||
LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_reverse(SBuf *sb, GCstr *s);
|
||||
LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_lower(SBuf *sb, GCstr *s);
|
||||
LJ_FUNCA SBuf * LJ_FASTCALL lj_buf_putstr_upper(SBuf *sb, GCstr *s);
|
||||
LJ_FUNC SBuf *lj_buf_putstr_rep(SBuf *sb, GCstr *s, int32_t rep);
|
||||
LJ_FUNCA GCstr * LJ_FASTCALL lj_buf_tostr(SBuf *sb);
|
||||
LJ_FUNC GCstr *lj_buf_cat2str(lua_State *L, GCstr *s1, GCstr *s2);
|
||||
LJ_FUNC uint32_t LJ_FASTCALL lj_buf_ruleb128(const char **pp);
|
||||
|
@ -61,7 +61,7 @@ typedef uint16_t HotCount;
|
||||
#define HOTCOUNT_CALL 1
|
||||
|
||||
/* This solves a circular dependency problem -- bump as needed. Sigh. */
|
||||
#define GG_NUM_ASMFF 58
|
||||
#define GG_NUM_ASMFF 57
|
||||
|
||||
#define GG_LEN_DDISP (BC__MAX + GG_NUM_ASMFF)
|
||||
#define GG_LEN_SDISP BC_FUNCF
|
||||
|
@ -1782,33 +1782,6 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| mvn CARG2, #~LJ_TSTR
|
||||
| b ->fff_restv
|
||||
|
|
||||
|.ffunc string_rep // Only handle the 1-char case inline.
|
||||
| ffgccheck
|
||||
| ldrd CARG12, [BASE]
|
||||
| ldrd CARG34, [BASE, #8]
|
||||
| cmp NARGS8:RC, #16
|
||||
| bne ->fff_fallback // Exactly 2 arguments
|
||||
| checktp CARG2, LJ_TSTR
|
||||
| checktpeq CARG4, LJ_TISNUM
|
||||
| bne ->fff_fallback
|
||||
| subs CARG4, CARG3, #1
|
||||
| ldr CARG2, STR:CARG1->len
|
||||
| blt ->fff_emptystr // Count <= 0?
|
||||
| cmp CARG2, #1
|
||||
| blo ->fff_emptystr // Zero-length string?
|
||||
| bne ->fff_fallback // Fallback for > 1-char strings.
|
||||
| ldr CARG2, [DISPATCH, #DISPATCH_GL(tmpbuf.b)]
|
||||
| ldr RB, [DISPATCH, #DISPATCH_GL(tmpbuf.e)]
|
||||
| ldr CARG1, STR:CARG1[1]
|
||||
| add INS, CARG2, CARG3
|
||||
| cmp RB, INS
|
||||
| blo ->fff_fallback
|
||||
|1: // Fill buffer with char.
|
||||
| strb CARG1, [CARG2, CARG4]
|
||||
| subs CARG4, CARG4, #1
|
||||
| bge <1
|
||||
| b ->fff_newstr
|
||||
|
|
||||
|.macro ffstring_op, name
|
||||
| .ffunc string_ .. name
|
||||
| ffgccheck
|
||||
|
@ -1716,41 +1716,6 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| b ->fff_restv
|
||||
|. li CARG3, LJ_TSTR
|
||||
|
|
||||
|.ffunc string_rep // Only handle the 1-char case inline.
|
||||
| ffgccheck
|
||||
| lw TMP0, HI(BASE)
|
||||
| addiu AT, NARGS8:RC, -16 // Exactly 2 arguments.
|
||||
| lw CARG4, 8+HI(BASE)
|
||||
| lw STR:CARG1, LO(BASE)
|
||||
| addiu TMP0, TMP0, -LJ_TSTR
|
||||
| ldc1 f0, 8(BASE)
|
||||
| or AT, AT, TMP0
|
||||
| bnez AT, ->fff_fallback
|
||||
|. sltiu AT, CARG4, LJ_TISNUM
|
||||
| trunc.w.d f0, f0
|
||||
| beqz AT, ->fff_fallback
|
||||
|. lw TMP0, STR:CARG1->len
|
||||
| mfc1 CARG3, f0
|
||||
| lw CARG2, DISPATCH_GL(tmpbuf.b)(DISPATCH)
|
||||
| lw TMP1, DISPATCH_GL(tmpbuf.e)(DISPATCH)
|
||||
| li AT, 1
|
||||
| blez CARG3, ->fff_emptystr // Count <= 0?
|
||||
|. sltu AT, AT, TMP0
|
||||
| beqz TMP0, ->fff_emptystr // Zero length string?
|
||||
|. addu TMP3, CARG2, CARG3
|
||||
| sltu TMP0, TMP1, TMP3
|
||||
| or AT, AT, TMP0
|
||||
| bnez AT, ->fff_fallback // Fallback for > 1-char strings.
|
||||
|. lbu TMP0, STR:CARG1[1]
|
||||
| addu TMP2, CARG2, CARG3
|
||||
|1: // Fill buffer with char. Yes, this is suboptimal code (do you care?).
|
||||
| addiu TMP2, TMP2, -1
|
||||
| sltu AT, CARG2, TMP2
|
||||
| bnez AT, <1
|
||||
|. sb TMP0, 0(TMP2)
|
||||
| b ->fff_newstr
|
||||
|. nop
|
||||
|
|
||||
|.macro ffstring_op, name
|
||||
| .ffunc string_ .. name
|
||||
| ffgccheck
|
||||
|
@ -2177,49 +2177,6 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| addi TMP1, TMP1, 1 // start = 1 + (start ? start+len : 0)
|
||||
| b <3
|
||||
|
|
||||
|.ffunc string_rep // Only handle the 1-char case inline.
|
||||
| ffgccheck
|
||||
| cmplwi NARGS8:RC, 16
|
||||
| lwz TMP0, 0(BASE)
|
||||
| lwz STR:CARG1, 4(BASE)
|
||||
| lwz CARG4, 8(BASE)
|
||||
|.if DUALNUM
|
||||
| lwz CARG3, 12(BASE)
|
||||
|.else
|
||||
| lfd FARG2, 8(BASE)
|
||||
|.endif
|
||||
| bne ->fff_fallback // Exactly 2 arguments.
|
||||
| checkstr TMP0; bne ->fff_fallback
|
||||
|.if DUALNUM
|
||||
| checknum CARG4; bne ->fff_fallback
|
||||
|.else
|
||||
| checknum CARG4; bge ->fff_fallback
|
||||
| toint CARG3, FARG2
|
||||
|.endif
|
||||
| lwz TMP0, STR:CARG1->len
|
||||
| cmpwi CARG3, 0
|
||||
| lwz TMP1, DISPATCH_GL(tmpbuf.e)(DISPATCH)
|
||||
| lwz CARG2, DISPATCH_GL(tmpbuf.b)(DISPATCH)
|
||||
| ble >2 // Count <= 0? (or non-int)
|
||||
| cmplwi TMP0, 1
|
||||
| add TMP3, CARG2, CARG3
|
||||
| subi TMP2, CARG3, 1
|
||||
| blt >2 // Zero length string?
|
||||
| cmplw cr1, TMP1, TMP3
|
||||
| bne ->fff_fallback // Fallback for > 1-char strings.
|
||||
| lbz TMP0, STR:CARG1[1]
|
||||
| blt cr1, ->fff_fallback
|
||||
|1: // Fill buffer with char. Yes, this is suboptimal code (do you care?).
|
||||
| cmplwi TMP2, 0
|
||||
| stbx TMP0, CARG2, TMP2
|
||||
| subi TMP2, TMP2, 1
|
||||
| bne <1
|
||||
| b ->fff_newstr
|
||||
|2: // Return empty string.
|
||||
| la STR:CARG1, DISPATCH_GL(strempty)(DISPATCH)
|
||||
| li CARG3, LJ_TSTR
|
||||
| b ->fff_restv
|
||||
|
|
||||
|.macro ffstring_op, name
|
||||
| .ffunc string_ .. name
|
||||
| ffgccheck
|
||||
|
@ -2331,41 +2331,6 @@ static void build_subroutines(BuildCtx *ctx)
|
||||
| xor RC, RC // Zero length. Any ptr in RB is ok.
|
||||
| jmp <4
|
||||
|
|
||||
|.ffunc string_rep // Only handle the 1-char case inline.
|
||||
| ffgccheck
|
||||
| cmp NARGS:RD, 2+1; jne ->fff_fallback // Exactly 2 arguments.
|
||||
| cmp dword [BASE+4], LJ_TSTR; jne ->fff_fallback
|
||||
| cmp dword [BASE+12], LJ_TISNUM
|
||||
| mov STR:RB, [BASE]
|
||||
|.if DUALNUM
|
||||
| jne ->fff_fallback
|
||||
| mov RC, dword [BASE+8]
|
||||
|.else
|
||||
| jae ->fff_fallback
|
||||
| cvttsd2si RC, qword [BASE+8]
|
||||
|.endif
|
||||
| test RC, RC
|
||||
| jle ->fff_emptystr // Count <= 0? (or non-int)
|
||||
| cmp dword STR:RB->len, 1
|
||||
| jb ->fff_emptystr // Zero length string?
|
||||
| jne ->fff_fallback_2 // Fallback for > 1-char strings.
|
||||
| movzx RA, byte STR:RB[1]
|
||||
| mov RB, [DISPATCH+DISPATCH_GL(tmpbuf.b)]
|
||||
| add RB, RC
|
||||
| cmp [DISPATCH+DISPATCH_GL(tmpbuf.e)], RB; jb ->fff_fallback_2
|
||||
|.if X64
|
||||
| mov TMP3, RC
|
||||
|.else
|
||||
| mov ARG3, RC
|
||||
|.endif
|
||||
|1: // Fill buffer with char.
|
||||
| sub RB, 1
|
||||
| sub RC, 1
|
||||
| mov [RB], RAL
|
||||
| jnz <1
|
||||
| mov RD, [DISPATCH+DISPATCH_GL(tmpbuf.b)]
|
||||
| jmp ->fff_newstr
|
||||
|
|
||||
|.macro ffstring_op, name
|
||||
| .ffunc_1 string_ .. name
|
||||
| ffgccheck
|
||||
|
Loading…
Reference in New Issue
Block a user