diff options
Diffstat (limited to 'src/lj_meta.c')
-rw-r--r-- | src/lj_meta.c | 125 |
1 files changed, 68 insertions, 57 deletions
diff --git a/src/lj_meta.c b/src/lj_meta.c index 6affc18b..7391ff00 100644 --- a/src/lj_meta.c +++ b/src/lj_meta.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "lj_obj.h" | 12 | #include "lj_obj.h" |
13 | #include "lj_gc.h" | 13 | #include "lj_gc.h" |
14 | #include "lj_err.h" | 14 | #include "lj_err.h" |
15 | #include "lj_buf.h" | ||
15 | #include "lj_str.h" | 16 | #include "lj_str.h" |
16 | #include "lj_tab.h" | 17 | #include "lj_tab.h" |
17 | #include "lj_meta.h" | 18 | #include "lj_meta.h" |
@@ -19,6 +20,8 @@ | |||
19 | #include "lj_bc.h" | 20 | #include "lj_bc.h" |
20 | #include "lj_vm.h" | 21 | #include "lj_vm.h" |
21 | #include "lj_strscan.h" | 22 | #include "lj_strscan.h" |
23 | #include "lj_strfmt.h" | ||
24 | #include "lj_lib.h" | ||
22 | 25 | ||
23 | /* -- Metamethod handling ------------------------------------------------- */ | 26 | /* -- Metamethod handling ------------------------------------------------- */ |
24 | 27 | ||
@@ -77,12 +80,16 @@ int lj_meta_tailcall(lua_State *L, cTValue *tv) | |||
77 | TValue *base = L->base; | 80 | TValue *base = L->base; |
78 | TValue *top = L->top; | 81 | TValue *top = L->top; |
79 | const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */ | 82 | const BCIns *pc = frame_pc(base-1); /* Preserve old PC from frame. */ |
80 | copyTV(L, base-1, tv); /* Replace frame with new object. */ | 83 | copyTV(L, base-1-LJ_FR2, tv); /* Replace frame with new object. */ |
81 | top->u32.lo = LJ_CONT_TAILCALL; | 84 | if (LJ_FR2) |
82 | setframe_pc(top, pc); | 85 | (top++)->u64 = LJ_CONT_TAILCALL; |
83 | setframe_gc(top+1, obj2gco(L)); /* Dummy frame object. */ | 86 | else |
84 | setframe_ftsz(top+1, (int)((char *)(top+2) - (char *)base) + FRAME_CONT); | 87 | top->u32.lo = LJ_CONT_TAILCALL; |
85 | L->base = L->top = top+2; | 88 | setframe_pc(top++, pc); |
89 | if (LJ_FR2) top++; | ||
90 | setframe_gc(top, obj2gco(L), LJ_TTHREAD); /* Dummy frame object. */ | ||
91 | setframe_ftsz(top, ((char *)(top+1) - (char *)base) + FRAME_CONT); | ||
92 | L->base = L->top = top+1; | ||
86 | /* | 93 | /* |
87 | ** before: [old_mo|PC] [... ...] | 94 | ** before: [old_mo|PC] [... ...] |
88 | ** ^base ^top | 95 | ** ^base ^top |
@@ -113,11 +120,13 @@ static TValue *mmcall(lua_State *L, ASMFunction cont, cTValue *mo, | |||
113 | */ | 120 | */ |
114 | TValue *top = L->top; | 121 | TValue *top = L->top; |
115 | if (curr_funcisL(L)) top = curr_topL(L); | 122 | if (curr_funcisL(L)) top = curr_topL(L); |
116 | setcont(top, cont); /* Assembler VM stores PC in upper word. */ | 123 | setcont(top++, cont); /* Assembler VM stores PC in upper word or FR2. */ |
117 | copyTV(L, top+1, mo); /* Store metamethod and two arguments. */ | 124 | if (LJ_FR2) setnilV(top++); |
118 | copyTV(L, top+2, a); | 125 | copyTV(L, top++, mo); /* Store metamethod and two arguments. */ |
119 | copyTV(L, top+3, b); | 126 | if (LJ_FR2) setnilV(top++); |
120 | return top+2; /* Return new base. */ | 127 | copyTV(L, top, a); |
128 | copyTV(L, top+1, b); | ||
129 | return top; /* Return new base. */ | ||
121 | } | 130 | } |
122 | 131 | ||
123 | /* -- C helpers for some instructions, called from assembler VM ----------- */ | 132 | /* -- C helpers for some instructions, called from assembler VM ----------- */ |
@@ -225,27 +234,14 @@ TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, | |||
225 | } | 234 | } |
226 | } | 235 | } |
227 | 236 | ||
228 | /* In-place coercion of a number to a string. */ | ||
229 | static LJ_AINLINE int tostring(lua_State *L, TValue *o) | ||
230 | { | ||
231 | if (tvisstr(o)) { | ||
232 | return 1; | ||
233 | } else if (tvisnumber(o)) { | ||
234 | setstrV(L, o, lj_str_fromnumber(L, o)); | ||
235 | return 1; | ||
236 | } else { | ||
237 | return 0; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ | 237 | /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ |
242 | TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | 238 | TValue *lj_meta_cat(lua_State *L, TValue *top, int left) |
243 | { | 239 | { |
244 | int fromc = 0; | 240 | int fromc = 0; |
245 | if (left < 0) { left = -left; fromc = 1; } | 241 | if (left < 0) { left = -left; fromc = 1; } |
246 | do { | 242 | do { |
247 | int n = 1; | 243 | if (!(tvisstr(top) || tvisnumber(top)) || |
248 | if (!(tvisstr(top-1) || tvisnumber(top-1)) || !tostring(L, top)) { | 244 | !(tvisstr(top-1) || tvisnumber(top-1))) { |
249 | cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); | 245 | cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); |
250 | if (tvisnil(mo)) { | 246 | if (tvisnil(mo)) { |
251 | mo = lj_meta_lookup(L, top, MM_concat); | 247 | mo = lj_meta_lookup(L, top, MM_concat); |
@@ -266,13 +262,12 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | |||
266 | ** after mm: [...][CAT stack ...] <--push-- [result] | 262 | ** after mm: [...][CAT stack ...] <--push-- [result] |
267 | ** next step: [...][CAT stack .............] | 263 | ** next step: [...][CAT stack .............] |
268 | */ | 264 | */ |
269 | copyTV(L, top+2, top); /* Careful with the order of stack copies! */ | 265 | copyTV(L, top+2*LJ_FR2+2, top); /* Carefully ordered stack copies! */ |
270 | copyTV(L, top+1, top-1); | 266 | copyTV(L, top+2*LJ_FR2+1, top-1); |
271 | copyTV(L, top, mo); | 267 | copyTV(L, top+LJ_FR2, mo); |
272 | setcont(top-1, lj_cont_cat); | 268 | setcont(top-1, lj_cont_cat); |
269 | if (LJ_FR2) { setnilV(top); setnilV(top+2); top += 2; } | ||
273 | return top+1; /* Trigger metamethod call. */ | 270 | return top+1; /* Trigger metamethod call. */ |
274 | } else if (strV(top)->len == 0) { /* Shortcut. */ | ||
275 | (void)tostring(L, top-1); | ||
276 | } else { | 271 | } else { |
277 | /* Pick as many strings as possible from the top and concatenate them: | 272 | /* Pick as many strings as possible from the top and concatenate them: |
278 | ** | 273 | ** |
@@ -281,27 +276,28 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | |||
281 | ** concat: [...][CAT stack ...] [result] | 276 | ** concat: [...][CAT stack ...] [result] |
282 | ** next step: [...][CAT stack ............] | 277 | ** next step: [...][CAT stack ............] |
283 | */ | 278 | */ |
284 | MSize tlen = strV(top)->len; | 279 | TValue *e, *o = top; |
285 | char *buffer; | 280 | uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; |
286 | int i; | 281 | SBuf *sb; |
287 | for (n = 1; n <= left && tostring(L, top-n); n++) { | 282 | do { |
288 | MSize len = strV(top-n)->len; | 283 | o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM; |
289 | if (len >= LJ_MAX_STR - tlen) | 284 | } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1))); |
290 | lj_err_msg(L, LJ_ERR_STROV); | 285 | if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV); |
291 | tlen += len; | 286 | sb = lj_buf_tmp_(L); |
292 | } | 287 | lj_buf_more(sb, (MSize)tlen); |
293 | buffer = lj_str_needbuf(L, &G(L)->tmpbuf, tlen); | 288 | for (e = top, top = o; o <= e; o++) { |
294 | n--; | 289 | if (tvisstr(o)) { |
295 | tlen = 0; | 290 | GCstr *s = strV(o); |
296 | for (i = n; i >= 0; i--) { | 291 | MSize len = s->len; |
297 | MSize len = strV(top-i)->len; | 292 | lj_buf_putmem(sb, strdata(s), len); |
298 | memcpy(buffer + tlen, strVdata(top-i), len); | 293 | } else if (tvisint(o)) { |
299 | tlen += len; | 294 | lj_strfmt_putint(sb, intV(o)); |
295 | } else { | ||
296 | lj_strfmt_putfnum(sb, STRFMT_G14, numV(o)); | ||
297 | } | ||
300 | } | 298 | } |
301 | setstrV(L, top-n, lj_str_new(L, buffer, tlen)); | 299 | setstrV(L, top, lj_buf_str(L, sb)); |
302 | } | 300 | } |
303 | left -= n; | ||
304 | top -= n; | ||
305 | } while (left >= 1); | 301 | } while (left >= 1); |
306 | if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { | 302 | if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { |
307 | if (!fromc) L->top = curr_topL(L); | 303 | if (!fromc) L->top = curr_topL(L); |
@@ -338,12 +334,14 @@ TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne) | |||
338 | return (TValue *)(intptr_t)ne; | 334 | return (TValue *)(intptr_t)ne; |
339 | } | 335 | } |
340 | top = curr_top(L); | 336 | top = curr_top(L); |
341 | setcont(top, ne ? lj_cont_condf : lj_cont_condt); | 337 | setcont(top++, ne ? lj_cont_condf : lj_cont_condt); |
342 | copyTV(L, top+1, mo); | 338 | if (LJ_FR2) setnilV(top++); |
339 | copyTV(L, top++, mo); | ||
340 | if (LJ_FR2) setnilV(top++); | ||
343 | it = ~(uint32_t)o1->gch.gct; | 341 | it = ~(uint32_t)o1->gch.gct; |
344 | setgcV(L, top+2, o1, it); | 342 | setgcV(L, top, o1, it); |
345 | setgcV(L, top+3, o2, it); | 343 | setgcV(L, top+1, o2, it); |
346 | return top+2; /* Trigger metamethod call. */ | 344 | return top; /* Trigger metamethod call. */ |
347 | } | 345 | } |
348 | return (TValue *)(intptr_t)ne; | 346 | return (TValue *)(intptr_t)ne; |
349 | } | 347 | } |
@@ -366,7 +364,7 @@ TValue * LJ_FASTCALL lj_meta_equal_cd(lua_State *L, BCIns ins) | |||
366 | o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)]; | 364 | o2 = &mref(curr_proto(L)->k, cTValue)[bc_d(ins)]; |
367 | } else { | 365 | } else { |
368 | lua_assert(op == BC_ISEQP); | 366 | lua_assert(op == BC_ISEQP); |
369 | setitype(&tv, ~bc_d(ins)); | 367 | setpriV(&tv, ~bc_d(ins)); |
370 | o2 = &tv; | 368 | o2 = &tv; |
371 | } | 369 | } |
372 | mo = lj_meta_lookup(L, o1mm, MM_eq); | 370 | mo = lj_meta_lookup(L, o1mm, MM_eq); |
@@ -423,6 +421,18 @@ TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op) | |||
423 | } | 421 | } |
424 | } | 422 | } |
425 | 423 | ||
424 | /* Helper for ISTYPE and ISNUM. Implicit coercion or error. */ | ||
425 | void lj_meta_istype(lua_State *L, BCReg ra, BCReg tp) | ||
426 | { | ||
427 | L->top = curr_topL(L); | ||
428 | ra++; tp--; | ||
429 | lua_assert(LJ_DUALNUM || tp != ~LJ_TNUMX); /* ISTYPE -> ISNUM broken. */ | ||
430 | if (LJ_DUALNUM && tp == ~LJ_TNUMX) lj_lib_checkint(L, ra); | ||
431 | else if (tp == ~LJ_TNUMX+1) lj_lib_checknum(L, ra); | ||
432 | else if (tp == ~LJ_TSTR) lj_lib_checkstr(L, ra); | ||
433 | else lj_err_argtype(L, ra, lj_obj_itypename[tp]); | ||
434 | } | ||
435 | |||
426 | /* Helper for calls. __call metamethod. */ | 436 | /* Helper for calls. __call metamethod. */ |
427 | void lj_meta_call(lua_State *L, TValue *func, TValue *top) | 437 | void lj_meta_call(lua_State *L, TValue *func, TValue *top) |
428 | { | 438 | { |
@@ -430,7 +440,8 @@ void lj_meta_call(lua_State *L, TValue *func, TValue *top) | |||
430 | TValue *p; | 440 | TValue *p; |
431 | if (!tvisfunc(mo)) | 441 | if (!tvisfunc(mo)) |
432 | lj_err_optype_call(L, func); | 442 | lj_err_optype_call(L, func); |
433 | for (p = top; p > func; p--) copyTV(L, p, p-1); | 443 | for (p = top; p > func+2*LJ_FR2; p--) copyTV(L, p, p-1); |
444 | if (LJ_FR2) copyTV(L, func+2, func); | ||
434 | copyTV(L, func, mo); | 445 | copyTV(L, func, mo); |
435 | } | 446 | } |
436 | 447 | ||