aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lj_meta.c58
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. */
231static 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. */
244TValue *lj_meta_cat(lua_State *L, TValue *top, int left) 231TValue *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);