diff options
-rw-r--r-- | src/lj_meta.c | 58 |
1 files changed, 22 insertions, 36 deletions
diff --git a/src/lj_meta.c b/src/lj_meta.c index db1ce928..2601af94 100644 --- a/src/lj_meta.c +++ b/src/lj_meta.c | |||
@@ -227,27 +227,14 @@ TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, | |||
227 | } | 227 | } |
228 | } | 228 | } |
229 | 229 | ||
230 | /* In-place coercion of a number to a string. */ | ||
231 | static LJ_AINLINE int tostring(lua_State *L, TValue *o) | ||
232 | { | ||
233 | if (tvisstr(o)) { | ||
234 | return 1; | ||
235 | } else if (tvisnumber(o)) { | ||
236 | setstrV(L, o, lj_str_fromnumber(L, o)); | ||
237 | return 1; | ||
238 | } else { | ||
239 | return 0; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ | 230 | /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ |
244 | TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | 231 | TValue *lj_meta_cat(lua_State *L, TValue *top, int left) |
245 | { | 232 | { |
246 | int fromc = 0; | 233 | int fromc = 0; |
247 | if (left < 0) { left = -left; fromc = 1; } | 234 | if (left < 0) { left = -left; fromc = 1; } |
248 | do { | 235 | do { |
249 | int n = 1; | 236 | if (!(tvisstr(top) || tvisnumber(top)) || |
250 | if (!(tvisstr(top-1) || tvisnumber(top-1)) || !tostring(L, top)) { | 237 | !(tvisstr(top-1) || tvisnumber(top-1))) { |
251 | cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); | 238 | cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); |
252 | if (tvisnil(mo)) { | 239 | if (tvisnil(mo)) { |
253 | mo = lj_meta_lookup(L, top, MM_concat); | 240 | mo = lj_meta_lookup(L, top, MM_concat); |
@@ -273,8 +260,6 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | |||
273 | copyTV(L, top, mo); | 260 | copyTV(L, top, mo); |
274 | setcont(top-1, lj_cont_cat); | 261 | setcont(top-1, lj_cont_cat); |
275 | return top+1; /* Trigger metamethod call. */ | 262 | return top+1; /* Trigger metamethod call. */ |
276 | } else if (strV(top)->len == 0) { /* Shortcut. */ | ||
277 | (void)tostring(L, top-1); | ||
278 | } else { | 263 | } else { |
279 | /* Pick as many strings as possible from the top and concatenate them: | 264 | /* Pick as many strings as possible from the top and concatenate them: |
280 | ** | 265 | ** |
@@ -283,27 +268,28 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | |||
283 | ** concat: [...][CAT stack ...] [result] | 268 | ** concat: [...][CAT stack ...] [result] |
284 | ** next step: [...][CAT stack ............] | 269 | ** next step: [...][CAT stack ............] |
285 | */ | 270 | */ |
286 | MSize tlen = strV(top)->len; | 271 | TValue *e, *o = top; |
287 | char *buf; | 272 | uint64_t tlen = tvisstr(o) ? strV(o)->len : LJ_STR_NUMBERBUF; |
288 | int i; | 273 | char *p, *buf; |
289 | for (n = 1; n <= left && tostring(L, top-n); n++) { | 274 | do { |
290 | MSize len = strV(top-n)->len; | 275 | o--; tlen += tvisstr(o) ? strV(o)->len : LJ_STR_NUMBERBUF; |
291 | if (len >= LJ_MAX_STR - tlen) | 276 | } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1))); |
292 | lj_err_msg(L, LJ_ERR_STROV); | 277 | if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV); |
293 | tlen += len; | 278 | p = buf = lj_buf_tmp(L, (MSize)tlen); |
294 | } | 279 | for (e = top, top = o; o <= e; o++) { |
295 | buf = lj_buf_tmp(L, tlen); | 280 | if (tvisstr(o)) { |
296 | n--; | 281 | GCstr *s = strV(o); |
297 | tlen = 0; | 282 | MSize len = s->len; |
298 | for (i = n; i >= 0; i--) { | 283 | p = lj_buf_wmem(p, strdata(s), len); |
299 | MSize len = strV(top-i)->len; | 284 | } else if (tvisint(o)) { |
300 | memcpy(buf + tlen, strVdata(top-i), len); | 285 | p = lj_str_bufint(p, intV(o)); |
301 | tlen += len; | 286 | } else { |
287 | lua_assert(tvisnum(o)); | ||
288 | p = lj_str_bufnum(p, o); | ||
289 | } | ||
302 | } | 290 | } |
303 | setstrV(L, top-n, lj_str_new(L, buf, tlen)); | 291 | setstrV(L, top, lj_str_new(L, buf, (size_t)(p-buf))); |
304 | } | 292 | } |
305 | left -= n; | ||
306 | top -= n; | ||
307 | } while (left >= 1); | 293 | } while (left >= 1); |
308 | if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { | 294 | if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { |
309 | if (!fromc) L->top = curr_topL(L); | 295 | if (!fromc) L->top = curr_topL(L); |