diff options
| -rw-r--r-- | doc/extensions.html | 25 | ||||
| -rw-r--r-- | src/Makefile.dep | 9 | ||||
| -rw-r--r-- | src/lj_bc.h | 11 | ||||
| -rw-r--r-- | src/lj_bcdump.h | 3 | ||||
| -rw-r--r-- | src/lj_bcwrite.c | 5 | ||||
| -rw-r--r-- | src/lj_carith.c | 31 | ||||
| -rw-r--r-- | src/lj_carith.h | 1 | ||||
| -rw-r--r-- | src/lj_crecord.c | 35 | ||||
| -rw-r--r-- | src/lj_crecord.h | 5 | ||||
| -rw-r--r-- | src/lj_dispatch.h | 1 | ||||
| -rw-r--r-- | src/lj_errmsg.h | 4 | ||||
| -rw-r--r-- | src/lj_ffrecord.c | 2 | ||||
| -rw-r--r-- | src/lj_ir.h | 2 | ||||
| -rw-r--r-- | src/lj_lex.c | 49 | ||||
| -rw-r--r-- | src/lj_lex.h | 12 | ||||
| -rw-r--r-- | src/lj_meta.c | 75 | ||||
| -rw-r--r-- | src/lj_meta.h | 2 | ||||
| -rw-r--r-- | src/lj_obj.h | 1 | ||||
| -rw-r--r-- | src/lj_opt_fold.c | 2 | ||||
| -rw-r--r-- | src/lj_parse.c | 781 | ||||
| -rw-r--r-- | src/lj_record.c | 40 | ||||
| -rw-r--r-- | src/vm_arm.dasc | 75 | ||||
| -rw-r--r-- | src/vm_arm64.dasc | 64 | ||||
| -rw-r--r-- | src/vm_mips.dasc | 75 | ||||
| -rw-r--r-- | src/vm_mips64.dasc | 77 | ||||
| -rw-r--r-- | src/vm_ppc.dasc | 100 | ||||
| -rw-r--r-- | src/vm_x64.dasc | 125 | ||||
| -rw-r--r-- | src/vm_x86.dasc | 132 |
28 files changed, 1510 insertions, 234 deletions
diff --git a/doc/extensions.html b/doc/extensions.html index 16e88505b..4668e192e 100644 --- a/doc/extensions.html +++ b/doc/extensions.html | |||
| @@ -411,6 +411,31 @@ LuaJIT supports some extensions from Lua 5.3: | |||
| 411 | </li> | 411 | </li> |
| 412 | </ul> | 412 | </ul> |
| 413 | 413 | ||
| 414 | <h2 id="lj30_bp_syntax">Backported Syntax Extensions from LuaJIT 3.0</h2> | ||
| 415 | <p> | ||
| 416 | LuaJIT 2.1 supports some | ||
| 417 | <a href="https://github.com/LuaJIT/LuaJIT/issues/1475#issuecomment-4769582883"><span class="ext">»</span> syntax extensions backported from LuaJIT 3.0</a>: | ||
| 418 | </p> | ||
| 419 | <ul> | ||
| 420 | <li>Bit Operators: unary <tt>~</tt>, binary <tt>& | ~ << >> ~>></tt></li> | ||
| 421 | <li>Customary Operators: <tt>! && || !=</tt></li> | ||
| 422 | <li>Ternary <tt>?:</tt> conditional operator</li> | ||
| 423 | <li>Safe Navigation Operator <tt>?.</tt></li> | ||
| 424 | <li>nil-Coalescing Operator <tt>??</tt></li> | ||
| 425 | <li>Compound Assignment Operators: <tt>+= -= *= /= %= &= |= ~= <<= >>= ~>>= ..=</tt></li> | ||
| 426 | <li><tt>continue</tt> Statement</li> | ||
| 427 | <li><tt>const</tt> Declaration</li> | ||
| 428 | <li>Short Function Expression</li> | ||
| 429 | <li>Underscores in Number Literals</li> | ||
| 430 | </ul> | ||
| 431 | <p> | ||
| 432 | Not backported are: | ||
| 433 | bit operator metamethods, | ||
| 434 | floor division operator <tt>//</tt>, | ||
| 435 | compound assignment metamethods, | ||
| 436 | named vararg parameter <tt>...name</tt>. | ||
| 437 | </p> | ||
| 438 | |||
| 414 | <h2 id="exceptions">C++ Exception Interoperability</h2> | 439 | <h2 id="exceptions">C++ Exception Interoperability</h2> |
| 415 | <p> | 440 | <p> |
| 416 | LuaJIT has built-in support for interoperating with C++ exceptions. | 441 | LuaJIT has built-in support for interoperating with C++ exceptions. |
diff --git a/src/Makefile.dep b/src/Makefile.dep index e10a6b29b..709107c2e 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep | |||
| @@ -149,7 +149,8 @@ lj_mcode.o: lj_mcode.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | |||
| 149 | lj_dispatch.h lj_bc.h lj_traceerr.h lj_prng.h lj_vm.h | 149 | lj_dispatch.h lj_bc.h lj_traceerr.h lj_prng.h lj_vm.h |
| 150 | lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 150 | lj_meta.o: lj_meta.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ |
| 151 | lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \ | 151 | lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_tab.h lj_meta.h lj_frame.h \ |
| 152 | lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h | 152 | lj_bc.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lib.h lj_ctype.h lj_cdata.h \ |
| 153 | lj_carith.h | ||
| 153 | lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h | 154 | lj_obj.o: lj_obj.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h |
| 154 | lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 155 | lj_opt_dce.o: lj_opt_dce.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 155 | lj_ir.h lj_jit.h lj_iropt.h | 156 | lj_ir.h lj_jit.h lj_iropt.h |
| @@ -181,9 +182,9 @@ lj_profile.o: lj_profile.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | |||
| 181 | lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h | 182 | lj_jit.h lj_ir.h lj_trace.h lj_traceerr.h lj_profile.h luajit.h |
| 182 | lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 183 | lj_record.o: lj_record.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
| 183 | lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ | 184 | lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_meta.h lj_frame.h lj_bc.h \ |
| 184 | lj_ctype.h lj_gc.h lj_ff.h lj_ffdef.h lj_debug.h lj_ir.h lj_jit.h \ | 185 | lj_ctype.h lj_gc.h lj_crecord.h lj_jit.h lj_ir.h lj_ffrecord.h lj_ff.h \ |
| 185 | lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h lj_traceerr.h \ | 186 | lj_ffdef.h lj_debug.h lj_ircall.h lj_iropt.h lj_trace.h lj_dispatch.h \ |
| 186 | lj_record.h lj_ffrecord.h lj_snap.h lj_vm.h lj_prng.h | 187 | lj_traceerr.h lj_record.h lj_snap.h lj_vm.h lj_prng.h |
| 187 | lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \ | 188 | lj_serialize.o: lj_serialize.c lj_obj.h lua.h luaconf.h lj_def.h \ |
| 188 | lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \ | 189 | lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h \ |
| 189 | lj_udata.h lj_ctype.h lj_cdata.h lj_ir.h lj_serialize.h | 190 | lj_udata.h lj_ctype.h lj_cdata.h lj_ir.h lj_serialize.h |
diff --git a/src/lj_bc.h b/src/lj_bc.h index 54d529e34..cbadc9abe 100644 --- a/src/lj_bc.h +++ b/src/lj_bc.h | |||
| @@ -98,7 +98,7 @@ | |||
| 98 | _(UNM, dst, ___, var, unm) \ | 98 | _(UNM, dst, ___, var, unm) \ |
| 99 | _(LEN, dst, ___, var, len) \ | 99 | _(LEN, dst, ___, var, len) \ |
| 100 | \ | 100 | \ |
| 101 | /* Binary ops. ORDER OPR. VV last, POW must be next. */ \ | 101 | /* Binary ops. ORDER OPR. ORDER ARITH. VV last, POW must be next. */ \ |
| 102 | _(ADDVN, dst, var, num, add) \ | 102 | _(ADDVN, dst, var, num, add) \ |
| 103 | _(SUBVN, dst, var, num, sub) \ | 103 | _(SUBVN, dst, var, num, sub) \ |
| 104 | _(MULVN, dst, var, num, mul) \ | 104 | _(MULVN, dst, var, num, mul) \ |
| @@ -186,6 +186,15 @@ | |||
| 186 | \ | 186 | \ |
| 187 | _(JMP, rbase, ___, jump, ___) \ | 187 | _(JMP, rbase, ___, jump, ___) \ |
| 188 | \ | 188 | \ |
| 189 | /* Bit operators. ORDER OPR. ORDER BIT. */ \ | ||
| 190 | _(BNOT, dst, ___, var, ___) \ | ||
| 191 | _(BAND, dst, var, var, ___) \ | ||
| 192 | _(BOR, dst, var, var, ___) \ | ||
| 193 | _(BXOR, dst, var, var, ___) \ | ||
| 194 | _(BSHL, dst, var, var, ___) \ | ||
| 195 | _(BSHR, dst, var, var, ___) \ | ||
| 196 | _(BSAR, dst, var, var, ___) \ | ||
| 197 | \ | ||
| 189 | /* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \ | 198 | /* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \ |
| 190 | _(FUNCF, rbase, ___, ___, ___) \ | 199 | _(FUNCF, rbase, ___, ___, ___) \ |
| 191 | _(IFUNCF, rbase, ___, ___, ___) \ | 200 | _(IFUNCF, rbase, ___, ___, ___) \ |
diff --git a/src/lj_bcdump.h b/src/lj_bcdump.h index 074ac0fda..3d2c95aca 100644 --- a/src/lj_bcdump.h +++ b/src/lj_bcdump.h | |||
| @@ -43,8 +43,9 @@ | |||
| 43 | #define BCDUMP_F_STRIP 0x02 | 43 | #define BCDUMP_F_STRIP 0x02 |
| 44 | #define BCDUMP_F_FFI 0x04 | 44 | #define BCDUMP_F_FFI 0x04 |
| 45 | #define BCDUMP_F_FR2 0x08 | 45 | #define BCDUMP_F_FR2 0x08 |
| 46 | #define BCDUMP_F_BITOP 0x10 | ||
| 46 | 47 | ||
| 47 | #define BCDUMP_F_KNOWN (BCDUMP_F_FR2*2-1) | 48 | #define BCDUMP_F_KNOWN (BCDUMP_F_BITOP*2-1) |
| 48 | 49 | ||
| 49 | #define BCDUMP_F_DETERMINISTIC 0x80000000 | 50 | #define BCDUMP_F_DETERMINISTIC 0x80000000 |
| 50 | 51 | ||
diff --git a/src/lj_bcwrite.c b/src/lj_bcwrite.c index a0230eff5..fb557e588 100644 --- a/src/lj_bcwrite.c +++ b/src/lj_bcwrite.c | |||
| @@ -340,7 +340,7 @@ static void bcwrite_proto(BCWriteCtx *ctx, GCproto *pt) | |||
| 340 | p += 5; /* Leave room for final size. */ | 340 | p += 5; /* Leave room for final size. */ |
| 341 | 341 | ||
| 342 | /* Write prototype header. */ | 342 | /* Write prototype header. */ |
| 343 | *p++ = (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI)); | 343 | *p++ = (pt->flags & (PROTO_CHILD|PROTO_VARARG|PROTO_FFI|PROTO_BITOP)); |
| 344 | *p++ = pt->numparams; | 344 | *p++ = pt->numparams; |
| 345 | *p++ = pt->framesize; | 345 | *p++ = pt->framesize; |
| 346 | *p++ = pt->sizeuv; | 346 | *p++ = pt->sizeuv; |
| @@ -397,7 +397,8 @@ static void bcwrite_header(BCWriteCtx *ctx) | |||
| 397 | *p++ = BCDUMP_VERSION; | 397 | *p++ = BCDUMP_VERSION; |
| 398 | *p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) + | 398 | *p++ = (ctx->flags & (BCDUMP_F_STRIP | BCDUMP_F_FR2)) + |
| 399 | LJ_BE*BCDUMP_F_BE + | 399 | LJ_BE*BCDUMP_F_BE + |
| 400 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0); | 400 | ((ctx->pt->flags & PROTO_FFI) ? BCDUMP_F_FFI : 0) + |
| 401 | ((ctx->pt->flags & PROTO_BITOP) ? BCDUMP_F_BITOP : 0); | ||
| 401 | if (!(ctx->flags & BCDUMP_F_STRIP)) { | 402 | if (!(ctx->flags & BCDUMP_F_STRIP)) { |
| 402 | p = lj_strfmt_wuleb128(p, len); | 403 | p = lj_strfmt_wuleb128(p, len); |
| 403 | p = lj_buf_wmem(p, name, len); | 404 | p = lj_buf_wmem(p, name, len); |
diff --git a/src/lj_carith.c b/src/lj_carith.c index cb408fb80..10f461580 100644 --- a/src/lj_carith.c +++ b/src/lj_carith.c | |||
| @@ -353,6 +353,37 @@ uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id) | |||
| 353 | } | 353 | } |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | /* Check bit operator arguments. No coercion from strings. */ | ||
| 357 | uint64_t lj_carith_checkbit64(lua_State *L, cTValue *o, CTypeID *id) | ||
| 358 | { | ||
| 359 | if (tviscdata(o)) { | ||
| 360 | CTState *cts = ctype_cts(L); | ||
| 361 | uint8_t *sp = (uint8_t *)cdataptr(cdataV(o)); | ||
| 362 | CTypeID sid = cdataV(o)->ctypeid; | ||
| 363 | CType *s = ctype_get(cts, sid); | ||
| 364 | uint64_t x; | ||
| 365 | if (ctype_isref(s->info)) { | ||
| 366 | sp = *(void **)sp; | ||
| 367 | sid = ctype_cid(s->info); | ||
| 368 | } | ||
| 369 | s = ctype_raw(cts, sid); | ||
| 370 | if (ctype_isenum(s->info)) s = ctype_child(cts, s); | ||
| 371 | if ((s->info & (CTMASK_NUM|CTF_BOOL|CTF_FP|CTF_UNSIGNED)) == | ||
| 372 | CTINFO(CT_NUM, CTF_UNSIGNED) && s->size == 8) | ||
| 373 | *id = CTID_UINT64; /* Use uint64_t, since it has the highest rank. */ | ||
| 374 | else if (!*id) | ||
| 375 | *id = CTID_INT64; /* Use int64_t, unless already set. */ | ||
| 376 | lj_cconv_ct_ct(cts, ctype_get(cts, *id), s, | ||
| 377 | (uint8_t *)&x, sp, 0); | ||
| 378 | return x; | ||
| 379 | } else if (LJ_LIKELY(tvisint(o))) { | ||
| 380 | return (uint64_t)intV(o); /* Sign-extended. */ | ||
| 381 | } else { | ||
| 382 | if (!tvisnum(o)) lj_err_optype(L, o, LJ_ERR_OPARITH); | ||
| 383 | return (uint64_t)lj_num2bit(numV(o)); /* Sign-extended. */ | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 356 | /* -- 64 bit integer arithmetic helpers ----------------------------------- */ | 387 | /* -- 64 bit integer arithmetic helpers ----------------------------------- */ |
| 357 | 388 | ||
| 358 | #if LJ_32 && LJ_HASJIT | 389 | #if LJ_32 && LJ_HASJIT |
diff --git a/src/lj_carith.h b/src/lj_carith.h index 93fa41f2b..700e48791 100644 --- a/src/lj_carith.h +++ b/src/lj_carith.h | |||
| @@ -21,6 +21,7 @@ LJ_FUNC uint64_t lj_carith_ror64(uint64_t x, int32_t sh); | |||
| 21 | #endif | 21 | #endif |
| 22 | LJ_FUNC uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op); | 22 | LJ_FUNC uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op); |
| 23 | LJ_FUNC uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id); | 23 | LJ_FUNC uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id); |
| 24 | LJ_FUNC uint64_t lj_carith_checkbit64(lua_State *L, cTValue *o, CTypeID *id); | ||
| 24 | 25 | ||
| 25 | #if LJ_32 && LJ_HASJIT | 26 | #if LJ_32 && LJ_HASJIT |
| 26 | LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k); | 27 | LJ_FUNC int64_t lj_carith_mul64(int64_t x, int64_t k); |
diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 4be36eca6..a8ea419a8 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c | |||
| @@ -1884,24 +1884,23 @@ int LJ_FASTCALL recff_bit64_nary(jit_State *J, RecordFFData *rd) | |||
| 1884 | return 0; | 1884 | return 0; |
| 1885 | } | 1885 | } |
| 1886 | 1886 | ||
| 1887 | int LJ_FASTCALL recff_bit64_shift(jit_State *J, RecordFFData *rd) | 1887 | int recff_bit64_shift(jit_State *J, TRef *rb, TRef *rc, |
| 1888 | TValue *rbv, TValue *rcv, IROp op) | ||
| 1888 | { | 1889 | { |
| 1889 | CTState *cts = ctype_ctsG(J2G(J)); | 1890 | CTState *cts = ctype_ctsG(J2G(J)); |
| 1890 | CTypeID id; | 1891 | CTypeID id; |
| 1891 | TRef tsh = 0; | 1892 | TRef tsh = 0; |
| 1892 | if (J->base[0] && tref_iscdata(J->base[1])) { | 1893 | if (*rb && tref_iscdata(*rc)) { |
| 1893 | tsh = crec_bit64_arg(J, ctype_get(cts, CTID_INT64), | 1894 | tsh = crec_bit64_arg(J, ctype_get(cts, CTID_INT64), *rc, rcv); |
| 1894 | J->base[1], &rd->argv[1]); | ||
| 1895 | if (LJ_32 && !tref_isinteger(tsh)) | 1895 | if (LJ_32 && !tref_isinteger(tsh)) |
| 1896 | tsh = emitconv(tsh, IRT_INT, tref_type(tsh), 0); | 1896 | tsh = emitconv(tsh, IRT_INT, tref_type(tsh), 0); |
| 1897 | J->base[1] = tsh; | 1897 | *rc = tsh; |
| 1898 | } | 1898 | } |
| 1899 | id = crec_bit64_type(cts, &rd->argv[0]); | 1899 | id = crec_bit64_type(cts, rbv); |
| 1900 | if (id) { | 1900 | if (id) { |
| 1901 | TRef tr = crec_bit64_arg(J, ctype_get(cts, id), J->base[0], &rd->argv[0]); | 1901 | TRef tr = crec_bit64_arg(J, ctype_get(cts, id), *rb, rbv); |
| 1902 | uint32_t op = rd->data; | ||
| 1903 | IRType t; | 1902 | IRType t; |
| 1904 | if (!tsh) tsh = lj_opt_narrow_tobit(J, J->base[1]); | 1903 | if (!tsh) tsh = lj_opt_narrow_tobit(J, *rc); |
| 1905 | t = tref_isinteger(tsh) ? IRT_INT : tref_type(tsh); | 1904 | t = tref_isinteger(tsh) ? IRT_INT : tref_type(tsh); |
| 1906 | if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && | 1905 | if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) && |
| 1907 | !tref_isk(tsh)) | 1906 | !tref_isk(tsh)) |
| @@ -1913,7 +1912,7 @@ int LJ_FASTCALL recff_bit64_shift(jit_State *J, RecordFFData *rd) | |||
| 1913 | } | 1912 | } |
| 1914 | #endif | 1913 | #endif |
| 1915 | tr = emitir(IRT(op, id-CTID_INT64+IRT_I64), tr, tsh); | 1914 | tr = emitir(IRT(op, id-CTID_INT64+IRT_I64), tr, tsh); |
| 1916 | J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); | 1915 | *rb = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); |
| 1917 | return 1; | 1916 | return 1; |
| 1918 | } | 1917 | } |
| 1919 | return 0; | 1918 | return 0; |
| @@ -1955,6 +1954,22 @@ TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr) | |||
| 1955 | return lj_ir_call(J, IRCALL_lj_strfmt_putfxint, hdr, lj_ir_kint(J, sf), tr); | 1954 | return lj_ir_call(J, IRCALL_lj_strfmt_putfxint, hdr, lj_ir_kint(J, sf), tr); |
| 1956 | } | 1955 | } |
| 1957 | 1956 | ||
| 1957 | TRef recff_bit64_bitop(jit_State *J, TRef rb, TRef rc, | ||
| 1958 | TValue *rbv, TValue *rcv, IROp op) | ||
| 1959 | { | ||
| 1960 | CTState *cts = ctype_ctsG(J2G(J)); | ||
| 1961 | CTypeID id = crec_bit64_type(cts, rbv); | ||
| 1962 | CTypeID id2 = rcv ? crec_bit64_type(cts, rcv) : 0; | ||
| 1963 | CType *ct; | ||
| 1964 | TRef tr, tr2; | ||
| 1965 | if (id < id2) id = id2; | ||
| 1966 | ct = ctype_get(cts, id); | ||
| 1967 | tr = crec_bit64_arg(J, ct, rb, rbv); | ||
| 1968 | tr2 = rcv ? crec_bit64_arg(J, ct, rc, rcv) : 0; | ||
| 1969 | tr = emitir(IRT(op, id-CTID_INT64+IRT_I64), tr, tr2); | ||
| 1970 | return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr); | ||
| 1971 | } | ||
| 1972 | |||
| 1958 | /* -- Miscellaneous library functions ------------------------------------- */ | 1973 | /* -- Miscellaneous library functions ------------------------------------- */ |
| 1959 | 1974 | ||
| 1960 | void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd) | 1975 | void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd) |
diff --git a/src/lj_crecord.h b/src/lj_crecord.h index ad99b7254..ad2d3e252 100644 --- a/src/lj_crecord.h +++ b/src/lj_crecord.h | |||
| @@ -29,8 +29,11 @@ LJ_FUNC void LJ_FASTCALL recff_ffi_gc(jit_State *J, RecordFFData *rd); | |||
| 29 | LJ_FUNC void LJ_FASTCALL recff_bit64_tobit(jit_State *J, RecordFFData *rd); | 29 | LJ_FUNC void LJ_FASTCALL recff_bit64_tobit(jit_State *J, RecordFFData *rd); |
| 30 | LJ_FUNC int LJ_FASTCALL recff_bit64_unary(jit_State *J, RecordFFData *rd); | 30 | LJ_FUNC int LJ_FASTCALL recff_bit64_unary(jit_State *J, RecordFFData *rd); |
| 31 | LJ_FUNC int LJ_FASTCALL recff_bit64_nary(jit_State *J, RecordFFData *rd); | 31 | LJ_FUNC int LJ_FASTCALL recff_bit64_nary(jit_State *J, RecordFFData *rd); |
| 32 | LJ_FUNC int LJ_FASTCALL recff_bit64_shift(jit_State *J, RecordFFData *rd); | 32 | LJ_FUNC int recff_bit64_shift(jit_State *J, TRef *rb, TRef *rc, |
| 33 | TValue *rbv, TValue *rcv, IROp op); | ||
| 33 | LJ_FUNC TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr); | 34 | LJ_FUNC TRef recff_bit64_tohex(jit_State *J, RecordFFData *rd, TRef hdr); |
| 35 | LJ_FUNC TRef recff_bit64_bitop(jit_State *J, TRef rb, TRef rc, | ||
| 36 | TValue *rbv, TValue *rcv, IROp op); | ||
| 34 | 37 | ||
| 35 | LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); | 38 | LJ_FUNC void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd); |
| 36 | LJ_FUNC TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o); | 39 | LJ_FUNC TRef lj_crecord_loadiu64(jit_State *J, TRef tr, cTValue *o); |
diff --git a/src/lj_dispatch.h b/src/lj_dispatch.h index 9baf762b2..755590e67 100644 --- a/src/lj_dispatch.h +++ b/src/lj_dispatch.h | |||
| @@ -49,6 +49,7 @@ extern double __divdf3(double a, double b); | |||
| 49 | _(lj_dispatch_profile) _(lj_err_throw) \ | 49 | _(lj_dispatch_profile) _(lj_err_throw) \ |
| 50 | _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ | 50 | _(lj_ffh_coroutine_wrap_err) _(lj_func_closeuv) _(lj_func_newL_gc) \ |
| 51 | _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ | 51 | _(lj_gc_barrieruv) _(lj_gc_step) _(lj_gc_step_fixtop) _(lj_meta_arith) \ |
| 52 | _(lj_meta_bitop) \ | ||
| 52 | _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ | 53 | _(lj_meta_call) _(lj_meta_cat) _(lj_meta_comp) _(lj_meta_equal) \ |
| 53 | _(lj_meta_for) _(lj_meta_istype) _(lj_meta_len) _(lj_meta_tget) \ | 54 | _(lj_meta_for) _(lj_meta_istype) _(lj_meta_len) _(lj_meta_tget) \ |
| 54 | _(lj_meta_tset) _(lj_state_growstack) _(lj_strfmt_number) \ | 55 | _(lj_meta_tset) _(lj_state_growstack) _(lj_strfmt_number) \ |
diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h index daf7fb6bf..ad8581c99 100644 --- a/src/lj_errmsg.h +++ b/src/lj_errmsg.h | |||
| @@ -140,9 +140,13 @@ ERRDEF(XDOTS, "cannot use " LUA_QL("...") " outside a vararg function") | |||
| 140 | ERRDEF(XSYNTAX, "syntax error") | 140 | ERRDEF(XSYNTAX, "syntax error") |
| 141 | ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") | 141 | ERRDEF(XFOR, LUA_QL("=") " or " LUA_QL("in") " expected") |
| 142 | ERRDEF(XBREAK, "no loop to break") | 142 | ERRDEF(XBREAK, "no loop to break") |
| 143 | ERRDEF(XCONT, "no loop to continue") | ||
| 143 | ERRDEF(XLUNDEF, "undefined label " LUA_QS) | 144 | ERRDEF(XLUNDEF, "undefined label " LUA_QS) |
| 144 | ERRDEF(XLDUP, "duplicate label " LUA_QS) | 145 | ERRDEF(XLDUP, "duplicate label " LUA_QS) |
| 145 | ERRDEF(XGSCOPE, "<goto %s> jumps into the scope of local " LUA_QS) | 146 | ERRDEF(XGSCOPE, "<goto %s> jumps into the scope of local " LUA_QS) |
| 147 | ERRDEF(XCSCOPE, "<continue> jumps into the scope of local " LUA_QS) | ||
| 148 | ERRDEF(XCONSTA, "attempt to assign to const variable " LUA_QS) | ||
| 149 | ERRDEF(XCONSTR, "attempt to re-declare const variable " LUA_QS) | ||
| 146 | 150 | ||
| 147 | /* Bytecode reader errors. */ | 151 | /* Bytecode reader errors. */ |
| 148 | ERRDEF(BCFMT, "cannot load incompatible bytecode") | 152 | ERRDEF(BCFMT, "cannot load incompatible bytecode") |
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index edbf13cc2..4349f748f 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c | |||
| @@ -745,7 +745,7 @@ static void LJ_FASTCALL recff_bit_nary(jit_State *J, RecordFFData *rd) | |||
| 745 | static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) | 745 | static void LJ_FASTCALL recff_bit_shift(jit_State *J, RecordFFData *rd) |
| 746 | { | 746 | { |
| 747 | #if LJ_HASFFI | 747 | #if LJ_HASFFI |
| 748 | if (recff_bit64_shift(J, rd)) | 748 | if (recff_bit64_shift(J, &J->base[0], &J->base[1], &rd->argv[0], &rd->argv[1], rd->data)) |
| 749 | return; | 749 | return; |
| 750 | #endif | 750 | #endif |
| 751 | { | 751 | { |
diff --git a/src/lj_ir.h b/src/lj_ir.h index b9f5e2c13..879196a52 100644 --- a/src/lj_ir.h +++ b/src/lj_ir.h | |||
| @@ -53,7 +53,7 @@ | |||
| 53 | _(KINT64, N , cst, ___) \ | 53 | _(KINT64, N , cst, ___) \ |
| 54 | _(KSLOT, N , ref, lit) \ | 54 | _(KSLOT, N , ref, lit) \ |
| 55 | \ | 55 | \ |
| 56 | /* Bit ops. */ \ | 56 | /* Bit ops. ORDER BIT */ \ |
| 57 | _(BNOT, N , ref, ___) \ | 57 | _(BNOT, N , ref, ___) \ |
| 58 | _(BSWAP, N , ref, ___) \ | 58 | _(BSWAP, N , ref, ___) \ |
| 59 | _(BAND, C , ref, ref) \ | 59 | _(BAND, C , ref, ref) \ |
diff --git a/src/lj_lex.c b/src/lj_lex.c index a585cb585..4bbe18359 100644 --- a/src/lj_lex.c +++ b/src/lj_lex.c | |||
| @@ -97,12 +97,18 @@ static void lex_number(LexState *ls, TValue *tv) | |||
| 97 | StrScanFmt fmt; | 97 | StrScanFmt fmt; |
| 98 | LexChar c, xp = 'e'; | 98 | LexChar c, xp = 'e'; |
| 99 | lj_assertLS(lj_char_isdigit(ls->c), "bad usage"); | 99 | lj_assertLS(lj_char_isdigit(ls->c), "bad usage"); |
| 100 | if ((c = ls->c) == '0' && (lex_savenext(ls) | 0x20) == 'x') | 100 | if ((c = ls->c) == '0') { |
| 101 | xp = 'p'; | 101 | lex_save(ls, c); |
| 102 | do { c = lex_next(ls); } while (c == '_'); | ||
| 103 | if ((c | 0x20) == 'x') xp = 'p'; | ||
| 104 | } | ||
| 102 | while (lj_char_isident(ls->c) || ls->c == '.' || | 105 | while (lj_char_isident(ls->c) || ls->c == '.' || |
| 103 | ((ls->c == '-' || ls->c == '+') && (c | 0x20) == xp)) { | 106 | ((ls->c == '-' || ls->c == '+') && (c | 0x20) == xp)) { |
| 104 | c = ls->c; | 107 | if (LJ_LIKELY(ls->c != '_')) { |
| 105 | lex_savenext(ls); | 108 | c = ls->c; |
| 109 | lex_save(ls, ls->c); | ||
| 110 | } | ||
| 111 | lex_next(ls); | ||
| 106 | } | 112 | } |
| 107 | lex_save(ls, '\0'); | 113 | lex_save(ls, '\0'); |
| 108 | fmt = lj_strscan_scan((const uint8_t *)ls->sb.b, sbuflen(&ls->sb)-1, tv, | 114 | fmt = lj_strscan_scan((const uint8_t *)ls->sb.b, sbuflen(&ls->sb)-1, tv, |
| @@ -321,7 +327,9 @@ static LexToken lex_scan(LexState *ls, TValue *tv) | |||
| 321 | continue; | 327 | continue; |
| 322 | case '-': | 328 | case '-': |
| 323 | lex_next(ls); | 329 | lex_next(ls); |
| 324 | if (ls->c != '-') return '-'; | 330 | if (ls->c != '-') { |
| 331 | if (ls->c != '>') return '-'; else { lex_next(ls); return TK_arrow; } | ||
| 332 | } | ||
| 325 | lex_next(ls); | 333 | lex_next(ls); |
| 326 | if (ls->c == '[') { /* Long comment "--[=*[...]=*]". */ | 334 | if (ls->c == '[') { /* Long comment "--[=*[...]=*]". */ |
| 327 | int sep = lex_skipeq(ls); | 335 | int sep = lex_skipeq(ls); |
| @@ -353,16 +361,41 @@ static LexToken lex_scan(LexState *ls, TValue *tv) | |||
| 353 | if (ls->c != '=') return '='; else { lex_next(ls); return TK_eq; } | 361 | if (ls->c != '=') return '='; else { lex_next(ls); return TK_eq; } |
| 354 | case '<': | 362 | case '<': |
| 355 | lex_next(ls); | 363 | lex_next(ls); |
| 356 | if (ls->c != '=') return '<'; else { lex_next(ls); return TK_le; } | 364 | if (ls->c == '=') { lex_next(ls); return TK_le; } |
| 365 | if (ls->c == '<') { lex_next(ls); return TK_shl; } | ||
| 366 | return '<'; | ||
| 357 | case '>': | 367 | case '>': |
| 358 | lex_next(ls); | 368 | lex_next(ls); |
| 359 | if (ls->c != '=') return '>'; else { lex_next(ls); return TK_ge; } | 369 | if (ls->c == '=') { lex_next(ls); return TK_ge; } |
| 370 | if (ls->c == '>') { lex_next(ls); return TK_shr; } | ||
| 371 | return '>'; | ||
| 360 | case '~': | 372 | case '~': |
| 361 | lex_next(ls); | 373 | lex_next(ls); |
| 362 | if (ls->c != '=') return '~'; else { lex_next(ls); return TK_ne; } | 374 | if (ls->c == '=') { lex_next(ls); return TK_ne; } |
| 375 | if (ls->c == '>') { | ||
| 376 | lex_next(ls); | ||
| 377 | if (ls->c != '>') lj_lex_error(ls, '~', LJ_ERR_XSYMBOL); | ||
| 378 | lex_next(ls); | ||
| 379 | return TK_sar; | ||
| 380 | } | ||
| 381 | return '~'; | ||
| 382 | case '!': | ||
| 383 | lex_next(ls); | ||
| 384 | if (ls->c != '=') return '!'; else { lex_next(ls); return TK_ne_; } | ||
| 363 | case ':': | 385 | case ':': |
| 364 | lex_next(ls); | 386 | lex_next(ls); |
| 365 | if (ls->c != ':') return ':'; else { lex_next(ls); return TK_label; } | 387 | if (ls->c != ':') return ':'; else { lex_next(ls); return TK_label; } |
| 388 | case '?': | ||
| 389 | lex_next(ls); | ||
| 390 | if (ls->c == '.') { lex_next(ls); return TK_nav; } | ||
| 391 | if (ls->c == '?') { lex_next(ls); return TK_coal; } | ||
| 392 | return '?'; | ||
| 393 | case '&': | ||
| 394 | lex_next(ls); | ||
| 395 | if (ls->c != '&') return '&'; else { lex_next(ls); return TK_and_; } | ||
| 396 | case '|': | ||
| 397 | lex_next(ls); | ||
| 398 | if (ls->c != '|') return '|'; else { lex_next(ls); return TK_or_; } | ||
| 366 | case '"': | 399 | case '"': |
| 367 | case '\'': | 400 | case '\'': |
| 368 | lex_string(ls, tv); | 401 | lex_string(ls, tv); |
diff --git a/src/lj_lex.h b/src/lj_lex.h index 8d5c9a336..e5b78337c 100644 --- a/src/lj_lex.h +++ b/src/lj_lex.h | |||
| @@ -13,10 +13,12 @@ | |||
| 13 | 13 | ||
| 14 | /* Lua lexer tokens. */ | 14 | /* Lua lexer tokens. */ |
| 15 | #define TKDEF(_, __) \ | 15 | #define TKDEF(_, __) \ |
| 16 | _(and) _(break) _(do) _(else) _(elseif) _(end) _(false) \ | 16 | _(and) _(break) _(const) _(continue) _(do) _(else) _(elseif) _(end) _(false) \ |
| 17 | _(for) _(function) _(goto) _(if) _(in) _(local) _(nil) _(not) _(or) \ | 17 | _(for) _(function) _(goto) _(if) _(in) _(local) _(nil) _(not) _(or) \ |
| 18 | _(repeat) _(return) _(then) _(true) _(until) _(while) \ | 18 | _(repeat) _(return) _(then) _(true) _(until) _(while) \ |
| 19 | __(concat, ..) __(dots, ...) __(eq, ==) __(ge, >=) __(le, <=) __(ne, ~=) \ | 19 | __(concat, ..) __(dots, ...) __(eq, ==) __(ge, >=) __(le, <=) __(ne, ~=) \ |
| 20 | __(nav, ?.) __(coal, \?\?) __(shl, <<) __(shr, >>) __(sar, ~>>) \ | ||
| 21 | __(and_, &&) __(or_, ||) __(ne_, !=) __(arrow, ->) \ | ||
| 20 | __(label, ::) __(number, <number>) __(name, <name>) __(string, <string>) \ | 22 | __(label, ::) __(number, <number>) __(name, <name>) __(string, <string>) \ |
| 21 | __(eof, <eof>) | 23 | __(eof, <eof>) |
| 22 | 24 | ||
| @@ -39,6 +41,12 @@ typedef struct BCInsLine { | |||
| 39 | BCLine line; /* Line number for this bytecode. */ | 41 | BCLine line; /* Line number for this bytecode. */ |
| 40 | } BCInsLine; | 42 | } BCInsLine; |
| 41 | 43 | ||
| 44 | /* Index into variable stack. */ | ||
| 45 | typedef uint16_t VarIndex; | ||
| 46 | |||
| 47 | #define LJ_VINDEX_HSIZE 32 /* Hash table size. Must be a power of 2. */ | ||
| 48 | #define LJ_VINDEX_MASK (LJ_VINDEX_HSIZE-1) | ||
| 49 | |||
| 42 | /* Info for local variables. Only used during bytecode generation. */ | 50 | /* Info for local variables. Only used during bytecode generation. */ |
| 43 | typedef struct VarInfo { | 51 | typedef struct VarInfo { |
| 44 | GCRef name; /* Local variable name or goto/label name. */ | 52 | GCRef name; /* Local variable name or goto/label name. */ |
| @@ -46,6 +54,7 @@ typedef struct VarInfo { | |||
| 46 | BCPos endpc; /* First point where the local variable is dead. */ | 54 | BCPos endpc; /* First point where the local variable is dead. */ |
| 47 | uint8_t slot; /* Variable slot. */ | 55 | uint8_t slot; /* Variable slot. */ |
| 48 | uint8_t info; /* Variable/goto/label info. */ | 56 | uint8_t info; /* Variable/goto/label info. */ |
| 57 | VarIndex prev; /* Previous entry in variable hash chain. */ | ||
| 49 | } VarInfo; | 58 | } VarInfo; |
| 50 | 59 | ||
| 51 | /* Lua lexer state. */ | 60 | /* Lua lexer state. */ |
| @@ -75,6 +84,7 @@ typedef struct LexState { | |||
| 75 | uint32_t level; /* Syntactical nesting level. */ | 84 | uint32_t level; /* Syntactical nesting level. */ |
| 76 | int endmark; /* Trust bytecode end marker, even if not at EOF. */ | 85 | int endmark; /* Trust bytecode end marker, even if not at EOF. */ |
| 77 | int fr2; /* Generate bytecode for LJ_FR2 mode. */ | 86 | int fr2; /* Generate bytecode for LJ_FR2 mode. */ |
| 87 | VarIndex vhash[LJ_VINDEX_HSIZE]; /* Variable hash chain anchors. */ | ||
| 78 | } LexState; | 88 | } LexState; |
| 79 | 89 | ||
| 80 | LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls); | 90 | LJ_FUNC int lj_lex_setup(lua_State *L, LexState *ls); |
diff --git a/src/lj_meta.c b/src/lj_meta.c index 1e7262a43..ddb37a1a3 100644 --- a/src/lj_meta.c +++ b/src/lj_meta.c | |||
| @@ -22,6 +22,11 @@ | |||
| 22 | #include "lj_strscan.h" | 22 | #include "lj_strscan.h" |
| 23 | #include "lj_strfmt.h" | 23 | #include "lj_strfmt.h" |
| 24 | #include "lj_lib.h" | 24 | #include "lj_lib.h" |
| 25 | #if LJ_HASFFI | ||
| 26 | #include "lj_ctype.h" | ||
| 27 | #include "lj_cdata.h" | ||
| 28 | #include "lj_carith.h" | ||
| 29 | #endif | ||
| 25 | 30 | ||
| 26 | /* -- Metamethod handling ------------------------------------------------- */ | 31 | /* -- Metamethod handling ------------------------------------------------- */ |
| 27 | 32 | ||
| @@ -234,6 +239,76 @@ TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, | |||
| 234 | } | 239 | } |
| 235 | } | 240 | } |
| 236 | 241 | ||
| 242 | /* Helper for bit operators. No bitop metamethods in v2.1. */ | ||
| 243 | void lj_meta_bitop(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc, BCReg op) | ||
| 244 | { | ||
| 245 | #if LJ_HASFFI | ||
| 246 | CTypeID id = 0, id_ignore = 0; | ||
| 247 | uint64_t b = lj_carith_checkbit64(L, rb, &id); | ||
| 248 | uint64_t c = lj_carith_checkbit64(L, rc, op >= BC_BSHL ? &id_ignore : &id); | ||
| 249 | if (id) { | ||
| 250 | if (tvisnum(rb)) { | ||
| 251 | b = id == CTID_UINT64 ? lj_num2u64(numV(rb)) : lj_num2i64(numV(rb)); | ||
| 252 | } | ||
| 253 | if (tvisnum(rc)) { | ||
| 254 | c = id == CTID_UINT64 ? lj_num2u64(numV(rc)) : lj_num2i64(numV(rc)); | ||
| 255 | } | ||
| 256 | } | ||
| 257 | switch (op) { | ||
| 258 | case BC_BNOT: b = ~b; break; | ||
| 259 | case BC_BAND: b &= c; break; | ||
| 260 | case BC_BOR: b |= c; break; | ||
| 261 | case BC_BXOR: b ^= c; break; | ||
| 262 | default: | ||
| 263 | if (id) { | ||
| 264 | b = lj_carith_shift64(b, (int32_t)c, op-BC_BSHL); | ||
| 265 | } else if (op == BC_BSHL) { | ||
| 266 | b = (uint64_t)((uint32_t)b << ((uint32_t)c & 31)); | ||
| 267 | } else if (op == BC_BSHR) { | ||
| 268 | b = (uint64_t)((uint32_t)b >> ((uint32_t)c & 31)); | ||
| 269 | } else { | ||
| 270 | lj_assertL(op == BC_BSAR, "bad bytecode op %d", op); | ||
| 271 | b = (uint64_t)(uint32_t)((int32_t)b >> ((uint32_t)c & 31)); | ||
| 272 | } | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | if (id) { | ||
| 276 | GCcdata *cd = lj_cdata_new_(L, id, 8); | ||
| 277 | *(uint64_t *)cdataptr(cd) = b; | ||
| 278 | setcdataV(L, ra, cd); | ||
| 279 | } else { | ||
| 280 | setintV(ra, (int32_t)b); | ||
| 281 | } | ||
| 282 | #else | ||
| 283 | #if LJ_DUALNUM | ||
| 284 | uint32_t b = 0, c = 0; | ||
| 285 | if (tvisint(rb)) b = (uint32_t)intV(rb); | ||
| 286 | else if (tvisnum(rb)) b = (uint32_t)lj_num2bit(numV(rb)); | ||
| 287 | else goto err; | ||
| 288 | if (tvisint(rc)) c = (uint32_t)intV(rc); | ||
| 289 | else if (tvisnum(rc)) c = (uint32_t)lj_num2bit(numV(rc)); | ||
| 290 | else goto err; | ||
| 291 | switch (op) { | ||
| 292 | case BC_BNOT: b = ~b; break; | ||
| 293 | case BC_BAND: b &= c; break; | ||
| 294 | case BC_BOR: b |= c; break; | ||
| 295 | case BC_BXOR: b ^= c; break; | ||
| 296 | case BC_BSHL: b <<= (c & 31); break; | ||
| 297 | case BC_BSHR: b >>= (c & 31); break; | ||
| 298 | case BC_BSAR: b = (uint32_t)((int32_t)b >> (c & 31)); break; | ||
| 299 | default: | ||
| 300 | lj_assertL(0, "bad bytecode op %d", op); | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | setintV(ra, (int32_t)b); | ||
| 304 | return; | ||
| 305 | err: | ||
| 306 | #endif | ||
| 307 | UNUSED(ra); UNUSED(op); | ||
| 308 | lj_err_optype(L, tvisnumber(rb) ? rc : rb, LJ_ERR_OPARITH); | ||
| 309 | #endif | ||
| 310 | } | ||
| 311 | |||
| 237 | /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ | 312 | /* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ |
| 238 | TValue *lj_meta_cat(lua_State *L, TValue *top, int left) | 313 | TValue *lj_meta_cat(lua_State *L, TValue *top, int left) |
| 239 | { | 314 | { |
diff --git a/src/lj_meta.h b/src/lj_meta.h index 3d6a71c05..28e6c8bb1 100644 --- a/src/lj_meta.h +++ b/src/lj_meta.h | |||
| @@ -26,6 +26,8 @@ LJ_FUNCA cTValue *lj_meta_tget(lua_State *L, cTValue *o, cTValue *k); | |||
| 26 | LJ_FUNCA TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k); | 26 | LJ_FUNCA TValue *lj_meta_tset(lua_State *L, cTValue *o, cTValue *k); |
| 27 | LJ_FUNCA TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, | 27 | LJ_FUNCA TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, |
| 28 | cTValue *rc, BCReg op); | 28 | cTValue *rc, BCReg op); |
| 29 | LJ_FUNCA void lj_meta_bitop(lua_State *L, TValue *ra, cTValue *rb, | ||
| 30 | cTValue *rc, BCReg op); | ||
| 29 | LJ_FUNCA TValue *lj_meta_cat(lua_State *L, TValue *top, int left); | 31 | LJ_FUNCA TValue *lj_meta_cat(lua_State *L, TValue *top, int left); |
| 30 | LJ_FUNCA TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o); | 32 | LJ_FUNCA TValue * LJ_FASTCALL lj_meta_len(lua_State *L, cTValue *o); |
| 31 | LJ_FUNCA TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne); | 33 | LJ_FUNCA TValue *lj_meta_equal(lua_State *L, GCobj *o1, GCobj *o2, int ne); |
diff --git a/src/lj_obj.h b/src/lj_obj.h index f380c78fc..96dc1e0d0 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h | |||
| @@ -401,6 +401,7 @@ typedef struct GCproto { | |||
| 401 | #define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */ | 401 | #define PROTO_FFI 0x04 /* Uses BC_KCDATA for FFI datatypes. */ |
| 402 | #define PROTO_NOJIT 0x08 /* JIT disabled for this function. */ | 402 | #define PROTO_NOJIT 0x08 /* JIT disabled for this function. */ |
| 403 | #define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */ | 403 | #define PROTO_ILOOP 0x10 /* Patched bytecode with ILOOP etc. */ |
| 404 | #define PROTO_BITOP 0x80 /* Uses bit operator bytecodes. */ | ||
| 404 | /* Only used during parsing. */ | 405 | /* Only used during parsing. */ |
| 405 | #define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */ | 406 | #define PROTO_HAS_RETURN 0x20 /* Already emitted a return. */ |
| 406 | #define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */ | 407 | #define PROTO_FIXUP_RETURN 0x40 /* Need to fixup emitted returns. */ |
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c index 7fc838373..cc2b9098c 100644 --- a/src/lj_opt_fold.c +++ b/src/lj_opt_fold.c | |||
| @@ -382,8 +382,8 @@ static uint64_t kfold_int64arith(jit_State *J, uint64_t k1, uint64_t k2, | |||
| 382 | case IR_BSAR: k1 = (uint64_t)((int64_t)k1 >> (k2 & 63)); break; | 382 | case IR_BSAR: k1 = (uint64_t)((int64_t)k1 >> (k2 & 63)); break; |
| 383 | case IR_BROL: k1 = lj_rol(k1, (k2 & 63)); break; | 383 | case IR_BROL: k1 = lj_rol(k1, (k2 & 63)); break; |
| 384 | case IR_BROR: k1 = lj_ror(k1, (k2 & 63)); break; | 384 | case IR_BROR: k1 = lj_ror(k1, (k2 & 63)); break; |
| 385 | default: lj_assertJ(0, "bad IR op %d", op); break; | ||
| 386 | #endif | 385 | #endif |
| 386 | default: lj_assertJ(0, "bad IR op %d", op); break; | ||
| 387 | } | 387 | } |
| 388 | return k1; | 388 | return k1; |
| 389 | } | 389 | } |
diff --git a/src/lj_parse.c b/src/lj_parse.c index 66e5a0341..00a64382c 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c | |||
| @@ -49,6 +49,7 @@ typedef enum { | |||
| 49 | VRELOCABLE, /* info = instruction PC */ | 49 | VRELOCABLE, /* info = instruction PC */ |
| 50 | VNONRELOC, /* info = result register */ | 50 | VNONRELOC, /* info = result register */ |
| 51 | VCALL, /* info = instruction PC, aux = base */ | 51 | VCALL, /* info = instruction PC, aux = base */ |
| 52 | VCALLNAV, /* info = instruction PC, aux = base */ | ||
| 52 | VVOID | 53 | VVOID |
| 53 | } ExpKind; | 54 | } ExpKind; |
| 54 | 55 | ||
| @@ -79,6 +80,18 @@ typedef struct ExpDesc { | |||
| 79 | #define expr_numtv(e) check_exp(expr_isnumk((e)), &(e)->u.nval) | 80 | #define expr_numtv(e) check_exp(expr_isnumk((e)), &(e)->u.nval) |
| 80 | #define expr_numberV(e) numberVnum(expr_numtv((e))) | 81 | #define expr_numberV(e) numberVnum(expr_numtv((e))) |
| 81 | 82 | ||
| 83 | /* Expression flags. */ | ||
| 84 | #define EXPR_F_NORES 0x01 /* Result will not be used. */ | ||
| 85 | #define EXPR_F_NOCOLON 0x02 /* Disallow colon for method call.*/ | ||
| 86 | #define EXPR_F_NONAV 0x04 /* Disallow safe navigation. */ | ||
| 87 | #define EXPR_F_RET1 0x08 /* Return a single expr. */ | ||
| 88 | |||
| 89 | static LJ_AINLINE int32_t expr_bitV(ExpDesc *e) | ||
| 90 | { | ||
| 91 | TValue *o = expr_numtv(e); | ||
| 92 | return tvisint(o) ? intV(o) : lj_num2bit(numV(o)); | ||
| 93 | } | ||
| 94 | |||
| 82 | /* Initialize expression. */ | 95 | /* Initialize expression. */ |
| 83 | static LJ_AINLINE void expr_init(ExpDesc *e, ExpKind k, uint32_t info) | 96 | static LJ_AINLINE void expr_init(ExpDesc *e, ExpKind k, uint32_t info) |
| 84 | { | 97 | { |
| @@ -107,17 +120,22 @@ typedef struct FuncScope { | |||
| 107 | #define FSCOPE_GOLA 0x04 /* Goto or label used in scope. */ | 120 | #define FSCOPE_GOLA 0x04 /* Goto or label used in scope. */ |
| 108 | #define FSCOPE_UPVAL 0x08 /* Upvalue in scope. */ | 121 | #define FSCOPE_UPVAL 0x08 /* Upvalue in scope. */ |
| 109 | #define FSCOPE_NOCLOSE 0x10 /* Do not close upvalues. */ | 122 | #define FSCOPE_NOCLOSE 0x10 /* Do not close upvalues. */ |
| 123 | #define FSCOPE_CONT 0x20 /* Continue used in scope. */ | ||
| 110 | 124 | ||
| 111 | #define NAME_BREAK ((GCstr *)(uintptr_t)1) | 125 | #define NAME_BREAK ((GCstr *)(uintptr_t)1) |
| 126 | #define NAME_CONT ((GCstr *)(uintptr_t)2) | ||
| 112 | 127 | ||
| 113 | /* Index into variable stack. */ | 128 | /* Index into variable stack. See VarIndex in lj_lex.h. */ |
| 114 | typedef uint16_t VarIndex; | 129 | #define VINDEX_NONE 0xffff |
| 115 | #define LJ_MAX_VSTACK (65536 - LJ_MAX_UPVAL) | 130 | #define LJ_MAX_VSTACK (65536 - LJ_MAX_UPVAL) |
| 116 | 131 | ||
| 132 | #define LJ_HASH_VSTACK 0x20 /* Must be a power of 2. */ | ||
| 133 | |||
| 117 | /* Variable/goto/label info. */ | 134 | /* Variable/goto/label info. */ |
| 118 | #define VSTACK_VAR_RW 0x01 /* R/W variable. */ | 135 | #define VSTACK_VAR_RW 0x01 /* R/W variable. */ |
| 119 | #define VSTACK_GOTO 0x02 /* Pending goto. */ | 136 | #define VSTACK_GOTO 0x02 /* Pending goto. */ |
| 120 | #define VSTACK_LABEL 0x04 /* Label. */ | 137 | #define VSTACK_LABEL 0x04 /* Label. */ |
| 138 | #define VSTACK_CONST 0x08 /* Constant variable. */ | ||
| 121 | 139 | ||
| 122 | /* Per-function state. */ | 140 | /* Per-function state. */ |
| 123 | typedef struct FuncState { | 141 | typedef struct FuncState { |
| @@ -148,10 +166,11 @@ typedef struct FuncState { | |||
| 148 | /* Binary and unary operators. ORDER OPR */ | 166 | /* Binary and unary operators. ORDER OPR */ |
| 149 | typedef enum BinOpr { | 167 | typedef enum BinOpr { |
| 150 | OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, /* ORDER ARITH */ | 168 | OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW, /* ORDER ARITH */ |
| 169 | OPR_BAND, OPR_BOR, OPR_BXOR, OPR_BSHL, OPR_BSHR, OPR_BSAR, /* ORDER BIT */ | ||
| 151 | OPR_CONCAT, | 170 | OPR_CONCAT, |
| 152 | OPR_NE, OPR_EQ, | 171 | OPR_NE, OPR_EQ, |
| 153 | OPR_LT, OPR_GE, OPR_LE, OPR_GT, | 172 | OPR_LT, OPR_GE, OPR_LE, OPR_GT, |
| 154 | OPR_AND, OPR_OR, | 173 | OPR_AND, OPR_OR, OPR_COAL, |
| 155 | OPR_NOBINOPR | 174 | OPR_NOBINOPR |
| 156 | } BinOpr; | 175 | } BinOpr; |
| 157 | 176 | ||
| @@ -458,7 +477,7 @@ static void expr_discharge(FuncState *fs, ExpDesc *e) | |||
| 458 | ins = BCINS_ABC(BC_TGETV, 0, e->u.s.info, rc); | 477 | ins = BCINS_ABC(BC_TGETV, 0, e->u.s.info, rc); |
| 459 | } | 478 | } |
| 460 | bcreg_free(fs, e->u.s.info); | 479 | bcreg_free(fs, e->u.s.info); |
| 461 | } else if (e->k == VCALL) { | 480 | } else if (e->k == VCALL || e->k == VCALLNAV) { |
| 462 | e->u.s.info = e->u.s.aux; | 481 | e->u.s.info = e->u.s.aux; |
| 463 | e->k = VNONRELOC; | 482 | e->k = VNONRELOC; |
| 464 | return; | 483 | return; |
| @@ -623,11 +642,13 @@ static void bcemit_store(FuncState *fs, ExpDesc *var, ExpDesc *e) | |||
| 623 | { | 642 | { |
| 624 | BCIns ins; | 643 | BCIns ins; |
| 625 | if (var->k == VLOCAL) { | 644 | if (var->k == VLOCAL) { |
| 645 | lj_assertFS(!(fs->ls->vstack[var->u.s.aux].info & VSTACK_CONST), "unchecked const assignment"); | ||
| 626 | fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW; | 646 | fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW; |
| 627 | expr_free(fs, e); | 647 | expr_free(fs, e); |
| 628 | expr_toreg(fs, e, var->u.s.info); | 648 | expr_toreg(fs, e, var->u.s.info); |
| 629 | return; | 649 | return; |
| 630 | } else if (var->k == VUPVAL) { | 650 | } else if (var->k == VUPVAL) { |
| 651 | lj_assertFS(!(fs->ls->vstack[var->u.s.aux].info & VSTACK_CONST), "unchecked const assignment"); | ||
| 631 | fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW; | 652 | fs->ls->vstack[var->u.s.aux].info |= VSTACK_VAR_RW; |
| 632 | expr_toval(fs, e); | 653 | expr_toval(fs, e); |
| 633 | if (e->k <= VKTRUE) | 654 | if (e->k <= VKTRUE) |
| @@ -793,17 +814,39 @@ static int foldarith(BinOpr opr, ExpDesc *e1, ExpDesc *e2) | |||
| 793 | return 1; | 814 | return 1; |
| 794 | } | 815 | } |
| 795 | 816 | ||
| 817 | /* Try constant-folding of bit operators. */ | ||
| 818 | static int foldbitop(BinOpr opr, ExpDesc *e1, ExpDesc *e2) | ||
| 819 | { | ||
| 820 | if (expr_isnumk_nojump(e1) && expr_isnumk_nojump(e2)) { | ||
| 821 | int32_t k1 = expr_bitV(e1), k2 = expr_bitV(e2); | ||
| 822 | switch (opr) { | ||
| 823 | case OPR_BAND: k1 &= k2; break; | ||
| 824 | case OPR_BOR: k1 |= k2; break; | ||
| 825 | case OPR_BXOR: k1 ^= k2; break; | ||
| 826 | case OPR_BSHL: k1 <<= (k2 & 31); break; | ||
| 827 | case OPR_BSHR: k1 = (int32_t)((uint32_t)k1 >> (k2 & 31)); break; | ||
| 828 | case OPR_BSAR: k1 >>= (k2 & 31); break; | ||
| 829 | default: lj_assertX(0, "bad OPR %d", opr); break; | ||
| 830 | } | ||
| 831 | setintV(&e1->u.nval, k1); | ||
| 832 | return 1; | ||
| 833 | } | ||
| 834 | return 0; | ||
| 835 | } | ||
| 836 | |||
| 796 | /* Emit arithmetic operator. */ | 837 | /* Emit arithmetic operator. */ |
| 797 | static void bcemit_arith(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2) | 838 | static void bcemit_arith(FuncState *fs, BinOpr opr, ExpDesc *e1, ExpDesc *e2) |
| 798 | { | 839 | { |
| 799 | BCReg rb, rc, t; | 840 | BCReg rb, rc, t; |
| 800 | uint32_t op; | 841 | uint32_t op; |
| 801 | if (foldarith(opr, e1, e2)) | ||
| 802 | return; | ||
| 803 | if (opr == OPR_POW) { | 842 | if (opr == OPR_POW) { |
| 804 | op = BC_POW; | 843 | op = BC_POW; |
| 805 | rc = expr_toanyreg(fs, e2); | 844 | rc = expr_toanyreg(fs, e2); |
| 806 | rb = expr_toanyreg(fs, e1); | 845 | rb = expr_toanyreg(fs, e1); |
| 846 | } else if (opr >= OPR_BAND) { | ||
| 847 | op = opr-OPR_BAND+BC_BAND; | ||
| 848 | rc = expr_toanyreg(fs, e2); | ||
| 849 | rb = expr_toanyreg(fs, e1); | ||
| 807 | } else { | 850 | } else { |
| 808 | op = opr-OPR_ADD+BC_ADDVV; | 851 | op = opr-OPR_ADD+BC_ADDVV; |
| 809 | /* Must discharge 2nd operand first since VINDEXED might free regs. */ | 852 | /* Must discharge 2nd operand first since VINDEXED might free regs. */ |
| @@ -887,6 +930,13 @@ static void bcemit_binop_left(FuncState *fs, BinOpr op, ExpDesc *e) | |||
| 887 | bcemit_branch_t(fs, e); | 930 | bcemit_branch_t(fs, e); |
| 888 | } else if (op == OPR_OR) { | 931 | } else if (op == OPR_OR) { |
| 889 | bcemit_branch_f(fs, e); | 932 | bcemit_branch_f(fs, e); |
| 933 | } else if (op == OPR_COAL) { | ||
| 934 | BCReg reg; | ||
| 935 | expr_tonextreg(fs, e); | ||
| 936 | reg = e->u.s.info; | ||
| 937 | bcemit_INS(fs, BCINS_AD(BC_ISNEP, reg, VKNIL)); | ||
| 938 | e->u.s.aux = bcemit_jmp(fs); | ||
| 939 | bcreg_free(fs, reg); | ||
| 890 | } else if (op == OPR_CONCAT) { | 940 | } else if (op == OPR_CONCAT) { |
| 891 | expr_tonextreg(fs, e); | 941 | expr_tonextreg(fs, e); |
| 892 | } else if (op == OPR_EQ || op == OPR_NE) { | 942 | } else if (op == OPR_EQ || op == OPR_NE) { |
| @@ -900,7 +950,12 @@ static void bcemit_binop_left(FuncState *fs, BinOpr op, ExpDesc *e) | |||
| 900 | static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2) | 950 | static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2) |
| 901 | { | 951 | { |
| 902 | if (op <= OPR_POW) { | 952 | if (op <= OPR_POW) { |
| 903 | bcemit_arith(fs, op, e1, e2); | 953 | if (!foldarith(op, e1, e2)) bcemit_arith(fs, op, e1, e2); |
| 954 | } else if (op <= OPR_BSAR) { | ||
| 955 | if (!foldbitop(op, e1, e2)) { | ||
| 956 | fs->flags |= PROTO_BITOP; | ||
| 957 | bcemit_arith(fs, op, e1, e2); | ||
| 958 | } | ||
| 904 | } else if (op == OPR_AND) { | 959 | } else if (op == OPR_AND) { |
| 905 | lj_assertFS(e1->t == NO_JMP, "jump list not closed"); | 960 | lj_assertFS(e1->t == NO_JMP, "jump list not closed"); |
| 906 | expr_discharge(fs, e2); | 961 | expr_discharge(fs, e2); |
| @@ -911,6 +966,9 @@ static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2) | |||
| 911 | expr_discharge(fs, e2); | 966 | expr_discharge(fs, e2); |
| 912 | jmp_append(fs, &e2->t, e1->t); | 967 | jmp_append(fs, &e2->t, e1->t); |
| 913 | *e1 = *e2; | 968 | *e1 = *e2; |
| 969 | } else if (op == OPR_COAL) { | ||
| 970 | expr_tonextreg(fs, e2); | ||
| 971 | jmp_tohere(fs, e1->u.s.aux); | ||
| 914 | } else if (op == OPR_CONCAT) { | 972 | } else if (op == OPR_CONCAT) { |
| 915 | expr_toval(fs, e2); | 973 | expr_toval(fs, e2); |
| 916 | if (e2->k == VRELOCABLE && bc_op(*bcptr(fs, e2)) == BC_CAT) { | 974 | if (e2->k == VRELOCABLE && bc_op(*bcptr(fs, e2)) == BC_CAT) { |
| @@ -961,34 +1019,41 @@ static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e) | |||
| 961 | lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k); | 1019 | lj_assertFS(e->k == VNONRELOC, "bad expr type %d", e->k); |
| 962 | } | 1020 | } |
| 963 | } else { | 1021 | } else { |
| 964 | lj_assertFS(op == BC_UNM || op == BC_LEN, "bad unop %d", op); | 1022 | lj_assertFS(op == BC_UNM || op == BC_LEN || op == BC_BNOT, "bad unop %d", op); |
| 965 | if (op == BC_UNM && !expr_hasjump(e)) { /* Constant-fold negations. */ | 1023 | if (!expr_hasjump(e)) { |
| 1024 | if (op == BC_UNM) { /* Constant-fold negations. */ | ||
| 966 | #if LJ_HASFFI | 1025 | #if LJ_HASFFI |
| 967 | if (e->k == VKCDATA) { /* Fold in-place since cdata is not interned. */ | 1026 | if (e->k == VKCDATA) { /* Fold in-place since cdata is not interned. */ |
| 968 | GCcdata *cd = cdataV(&e->u.nval); | 1027 | GCcdata *cd = cdataV(&e->u.nval); |
| 969 | uint64_t *p = (uint64_t *)cdataptr(cd); | 1028 | uint64_t *p = (uint64_t *)cdataptr(cd); |
| 970 | if (cd->ctypeid == CTID_COMPLEX_DOUBLE) | 1029 | if (cd->ctypeid == CTID_COMPLEX_DOUBLE) |
| 971 | p[1] ^= U64x(80000000,00000000); | 1030 | p[1] ^= U64x(80000000,00000000); |
| 972 | else | ||
| 973 | *p = ~*p+1u; | ||
| 974 | return; | ||
| 975 | } else | ||
| 976 | #endif | ||
| 977 | if (expr_isnumk(e) && !expr_numiszero(e)) { /* Avoid folding to -0. */ | ||
| 978 | TValue *o = expr_numtv(e); | ||
| 979 | if (tvisint(o)) { | ||
| 980 | int32_t k = intV(o), negk = (int32_t)(~(uint32_t)k+1u); | ||
| 981 | if (k == negk) | ||
| 982 | setnumV(o, -(lua_Number)k); | ||
| 983 | else | 1031 | else |
| 984 | setintV(o, negk); | 1032 | *p = ~*p+1u; |
| 985 | return; | ||
| 986 | } else { | ||
| 987 | o->u64 ^= U64x(80000000,00000000); | ||
| 988 | return; | 1033 | return; |
| 1034 | } else | ||
| 1035 | #endif | ||
| 1036 | if (expr_isnumk(e) && !expr_numiszero(e)) { /* Avoid folding to -0. */ | ||
| 1037 | TValue *o = expr_numtv(e); | ||
| 1038 | if (tvisint(o)) { | ||
| 1039 | int32_t k = intV(o), negk = (int32_t)(~(uint32_t)k+1u); | ||
| 1040 | if (k == negk) | ||
| 1041 | setnumV(o, -(lua_Number)k); | ||
| 1042 | else | ||
| 1043 | setintV(o, negk); | ||
| 1044 | return; | ||
| 1045 | } else { | ||
| 1046 | o->u64 ^= U64x(80000000,00000000); | ||
| 1047 | return; | ||
| 1048 | } | ||
| 989 | } | 1049 | } |
| 1050 | } else if (op == BC_BNOT && expr_isnumk(e)) { | ||
| 1051 | /* Constant-fold bitwise not. */ | ||
| 1052 | setintV(&e->u.nval, (int32_t)~(uint32_t)expr_bitV(e)); | ||
| 1053 | return; | ||
| 990 | } | 1054 | } |
| 991 | } | 1055 | } |
| 1056 | if (op == BC_BNOT) fs->flags |= PROTO_BITOP; | ||
| 992 | expr_toanyreg(fs, e); | 1057 | expr_toanyreg(fs, e); |
| 993 | } | 1058 | } |
| 994 | expr_free(fs, e); | 1059 | expr_free(fs, e); |
| @@ -1030,11 +1095,20 @@ static void lex_match(LexState *ls, LexToken what, LexToken who, BCLine line) | |||
| 1030 | } | 1095 | } |
| 1031 | } | 1096 | } |
| 1032 | 1097 | ||
| 1098 | /* Check for a name, including soft keywords. */ | ||
| 1099 | static LJ_AINLINE int lex_isname(LexToken tok) | ||
| 1100 | { | ||
| 1101 | return (tok == TK_name || | ||
| 1102 | (!LJ_52 && tok == TK_goto) || | ||
| 1103 | tok == TK_continue || | ||
| 1104 | tok == TK_const); | ||
| 1105 | } | ||
| 1106 | |||
| 1033 | /* Check for string token. */ | 1107 | /* Check for string token. */ |
| 1034 | static GCstr *lex_str(LexState *ls) | 1108 | static GCstr *lex_str(LexState *ls) |
| 1035 | { | 1109 | { |
| 1036 | GCstr *s; | 1110 | GCstr *s; |
| 1037 | if (ls->tok != TK_name && (LJ_52 || ls->tok != TK_goto)) | 1111 | if (!lex_isname(ls->tok)) |
| 1038 | err_token(ls, TK_name); | 1112 | err_token(ls, TK_name); |
| 1039 | s = strV(&ls->tokval); | 1113 | s = strV(&ls->tokval); |
| 1040 | lj_lex_next(ls); | 1114 | lj_lex_next(ls); |
| @@ -1045,11 +1119,31 @@ static GCstr *lex_str(LexState *ls) | |||
| 1045 | 1119 | ||
| 1046 | #define var_get(ls, fs, i) ((ls)->vstack[(fs)->varmap[(i)]]) | 1120 | #define var_get(ls, fs, i) ((ls)->vstack[(fs)->varmap[(i)]]) |
| 1047 | 1121 | ||
| 1122 | typedef intptr_t VarHash; /* For performance reasons. */ | ||
| 1123 | |||
| 1124 | /* Hash of a variable name. */ | ||
| 1125 | static LJ_AINLINE VarHash var_hash(GCstr *name) | ||
| 1126 | { | ||
| 1127 | if ((uintptr_t)name < VARNAME__MAX) | ||
| 1128 | return -1; | ||
| 1129 | else | ||
| 1130 | return (name->sid & LJ_VINDEX_MASK); /* Immutable id, not name->hash! */ | ||
| 1131 | } | ||
| 1132 | |||
| 1048 | /* Define a new local variable. */ | 1133 | /* Define a new local variable. */ |
| 1049 | static void var_new(LexState *ls, BCReg n, GCstr *name) | 1134 | static MSize var_new(LexState *ls, BCReg n, GCstr *name) |
| 1050 | { | 1135 | { |
| 1051 | FuncState *fs = ls->fs; | 1136 | FuncState *fs = ls->fs; |
| 1052 | MSize vtop = ls->vtop; | 1137 | MSize vtop = ls->vtop; |
| 1138 | if ((uintptr_t)name >= VARNAME__MAX) { /* Check for const re-declaration. */ | ||
| 1139 | MSize vidx = ls->vhash[var_hash(name)]; | ||
| 1140 | while (vidx != VINDEX_NONE) { | ||
| 1141 | VarInfo *v = &ls->vstack[vidx]; | ||
| 1142 | if (strref(v->name) == name && (v->info & VSTACK_CONST)) | ||
| 1143 | lj_lex_error(ls, 0, LJ_ERR_XCONSTR, strdata(name)); | ||
| 1144 | vidx = v->prev; | ||
| 1145 | } | ||
| 1146 | } | ||
| 1053 | checklimit(fs, fs->nactvar+n, LJ_MAX_LOCVAR, "local variables"); | 1147 | checklimit(fs, fs->nactvar+n, LJ_MAX_LOCVAR, "local variables"); |
| 1054 | if (LJ_UNLIKELY(vtop >= ls->sizevstack)) { | 1148 | if (LJ_UNLIKELY(vtop >= ls->sizevstack)) { |
| 1055 | if (ls->sizevstack >= LJ_MAX_VSTACK) | 1149 | if (ls->sizevstack >= LJ_MAX_VSTACK) |
| @@ -1061,8 +1155,11 @@ static void var_new(LexState *ls, BCReg n, GCstr *name) | |||
| 1061 | "unanchored variable name"); | 1155 | "unanchored variable name"); |
| 1062 | /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ | 1156 | /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ |
| 1063 | setgcref(ls->vstack[vtop].name, obj2gco(name)); | 1157 | setgcref(ls->vstack[vtop].name, obj2gco(name)); |
| 1158 | ls->vstack[vtop].info = 0; | ||
| 1159 | /* The other VarInfo fields are filled in by var_add and var_remove. */ | ||
| 1064 | fs->varmap[fs->nactvar+n] = (uint16_t)vtop; | 1160 | fs->varmap[fs->nactvar+n] = (uint16_t)vtop; |
| 1065 | ls->vtop = vtop+1; | 1161 | ls->vtop = vtop+1; |
| 1162 | return vtop; | ||
| 1066 | } | 1163 | } |
| 1067 | 1164 | ||
| 1068 | #define var_new_lit(ls, n, v) \ | 1165 | #define var_new_lit(ls, n, v) \ |
| @@ -1077,10 +1174,15 @@ static void var_add(LexState *ls, BCReg nvars) | |||
| 1077 | FuncState *fs = ls->fs; | 1174 | FuncState *fs = ls->fs; |
| 1078 | BCReg nactvar = fs->nactvar; | 1175 | BCReg nactvar = fs->nactvar; |
| 1079 | while (nvars--) { | 1176 | while (nvars--) { |
| 1080 | VarInfo *v = &var_get(ls, fs, nactvar); | 1177 | intptr_t vidx = fs->varmap[nactvar]; |
| 1178 | VarInfo *v = &ls->vstack[vidx]; | ||
| 1179 | VarHash hash = var_hash(strref(v->name)); | ||
| 1081 | v->startpc = fs->pc; | 1180 | v->startpc = fs->pc; |
| 1082 | v->slot = nactvar++; | 1181 | v->slot = nactvar++; |
| 1083 | v->info = 0; | 1182 | if (hash != -1) { |
| 1183 | v->prev = ls->vhash[hash]; | ||
| 1184 | ls->vhash[hash] = vidx; | ||
| 1185 | } | ||
| 1084 | } | 1186 | } |
| 1085 | fs->nactvar = nactvar; | 1187 | fs->nactvar = nactvar; |
| 1086 | } | 1188 | } |
| @@ -1089,70 +1191,86 @@ static void var_add(LexState *ls, BCReg nvars) | |||
| 1089 | static void var_remove(LexState *ls, BCReg tolevel) | 1191 | static void var_remove(LexState *ls, BCReg tolevel) |
| 1090 | { | 1192 | { |
| 1091 | FuncState *fs = ls->fs; | 1193 | FuncState *fs = ls->fs; |
| 1092 | while (fs->nactvar > tolevel) | 1194 | while (fs->nactvar > tolevel) { |
| 1093 | var_get(ls, fs, --fs->nactvar).endpc = fs->pc; | 1195 | VarInfo *v = &var_get(ls, fs, --fs->nactvar); |
| 1094 | } | 1196 | VarHash hash = var_hash(strref(v->name)); |
| 1095 | 1197 | v->endpc = fs->pc; | |
| 1096 | /* Lookup local variable name. */ | 1198 | if (hash != -1) { |
| 1097 | static BCReg var_lookup_local(FuncState *fs, GCstr *n) | 1199 | ls->vhash[hash] = v->prev; |
| 1098 | { | 1200 | } |
| 1099 | int i; | ||
| 1100 | for (i = fs->nactvar-1; i >= 0; i--) { | ||
| 1101 | if (n == strref(var_get(fs->ls, fs, i).name)) | ||
| 1102 | return (BCReg)i; | ||
| 1103 | } | 1201 | } |
| 1104 | return (BCReg)-1; /* Not found. */ | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | /* Lookup or add upvalue index. */ | ||
| 1108 | static MSize var_lookup_uv(FuncState *fs, MSize vidx, ExpDesc *e) | ||
| 1109 | { | ||
| 1110 | MSize i, n = fs->nuv; | ||
| 1111 | for (i = 0; i < n; i++) | ||
| 1112 | if (fs->uvmap[i] == vidx) | ||
| 1113 | return i; /* Already exists. */ | ||
| 1114 | /* Otherwise create a new one. */ | ||
| 1115 | checklimit(fs, fs->nuv, LJ_MAX_UPVAL, "upvalues"); | ||
| 1116 | lj_assertFS(e->k == VLOCAL || e->k == VUPVAL, "bad expr type %d", e->k); | ||
| 1117 | fs->uvmap[n] = (uint16_t)vidx; | ||
| 1118 | fs->uvtmp[n] = (uint16_t)(e->k == VLOCAL ? vidx : LJ_MAX_VSTACK+e->u.s.info); | ||
| 1119 | fs->nuv = n+1; | ||
| 1120 | return n; | ||
| 1121 | } | 1202 | } |
| 1122 | 1203 | ||
| 1123 | /* Forward declaration. */ | 1204 | /* Forward declaration. */ |
| 1124 | static void fscope_uvmark(FuncState *fs, BCReg level); | 1205 | static void fscope_uvmark(FuncState *fs, BCReg level); |
| 1125 | 1206 | ||
| 1126 | /* Recursively lookup variables in enclosing functions. */ | 1207 | /* Lookup variable name. */ |
| 1127 | static MSize var_lookup_(FuncState *fs, GCstr *name, ExpDesc *e, int first) | 1208 | static MSize var_lookup(LexState *ls, ExpDesc *e, GCstr *name) |
| 1128 | { | 1209 | { |
| 1129 | if (fs) { | 1210 | MSize vidx = ls->vhash[var_hash(name)]; |
| 1130 | BCReg reg = var_lookup_local(fs, name); | 1211 | while (vidx != VINDEX_NONE) { |
| 1131 | if ((int32_t)reg >= 0) { /* Local in this function? */ | 1212 | VarInfo *v = &ls->vstack[vidx]; |
| 1132 | expr_init(e, VLOCAL, reg); | 1213 | if (strref(v->name) == name) { |
| 1133 | if (!first) | 1214 | FuncState *fs = ls->fs; |
| 1134 | fscope_uvmark(fs, reg); /* Scope now has an upvalue. */ | 1215 | if (vidx >= fs->vbase) { |
| 1135 | return (MSize)(e->u.s.aux = (uint32_t)fs->varmap[reg]); | 1216 | expr_init(e, VLOCAL, v->slot); |
| 1136 | } else { | 1217 | e->u.s.aux = vidx; |
| 1137 | MSize vidx = var_lookup_(fs->prev, name, e, 0); /* Var in outer func? */ | 1218 | } else { |
| 1138 | if ((int32_t)vidx >= 0) { /* Yes, make it an upvalue here. */ | 1219 | MSize uvidx, nuv = fs->nuv; |
| 1139 | e->u.s.info = (uint8_t)var_lookup_uv(fs, vidx, e); | 1220 | e->u.s.aux = vidx; |
| 1140 | e->k = VUPVAL; | 1221 | for (uvidx = 0; uvidx < nuv; uvidx++) { |
| 1141 | return vidx; | 1222 | if (fs->uvmap[uvidx] == vidx) { /* Upvalue already exists. */ |
| 1223 | expr_init(e, VUPVAL, uvidx); | ||
| 1224 | return vidx; | ||
| 1225 | } | ||
| 1226 | } | ||
| 1227 | expr_init(e, VUPVAL, nuv); | ||
| 1228 | for (;;) { | ||
| 1229 | /* Create a new upvalue. */ | ||
| 1230 | VarIndex *puvtmp; | ||
| 1231 | checklimit(fs, nuv, LJ_MAX_UPVAL, "upvalues"); | ||
| 1232 | fs->uvmap[nuv] = (uint16_t)vidx; | ||
| 1233 | fs->nuv = nuv + 1; | ||
| 1234 | puvtmp = &fs->uvtmp[nuv]; /* Set below. */ | ||
| 1235 | fs = fs->prev; /* Continue in parent. */ | ||
| 1236 | lj_assertLS(fs != NULL, "variable hash chain broken"); | ||
| 1237 | if (vidx >= fs->vbase) { /* Local in that function. */ | ||
| 1238 | *puvtmp = vidx; | ||
| 1239 | fscope_uvmark(fs, v->slot); | ||
| 1240 | return vidx; | ||
| 1241 | } | ||
| 1242 | /* Not a local in that function. Find or create upvalue. */ | ||
| 1243 | nuv = fs->nuv; | ||
| 1244 | for (uvidx = 0; uvidx < nuv; uvidx++) { | ||
| 1245 | if (fs->uvmap[uvidx] == vidx) { /* Upvalue already exists. */ | ||
| 1246 | *puvtmp = LJ_MAX_VSTACK + uvidx; | ||
| 1247 | return vidx; | ||
| 1248 | } | ||
| 1249 | } | ||
| 1250 | /* Not yet an upvalue. Create it and continue. */ | ||
| 1251 | *puvtmp = LJ_MAX_VSTACK + nuv; | ||
| 1252 | } | ||
| 1142 | } | 1253 | } |
| 1254 | return vidx; | ||
| 1143 | } | 1255 | } |
| 1144 | } else { /* Not found in any function, must be a global. */ | 1256 | vidx = v->prev; |
| 1145 | expr_init(e, VGLOBAL, 0); | ||
| 1146 | e->u.sval = name; | ||
| 1147 | } | 1257 | } |
| 1148 | return (MSize)-1; /* Global. */ | 1258 | expr_init(e, VGLOBAL, 0); |
| 1259 | e->u.sval = name; | ||
| 1260 | return vidx; | ||
| 1149 | } | 1261 | } |
| 1150 | 1262 | ||
| 1151 | /* Lookup variable name. */ | 1263 | /* Check for const variable assignment. */ |
| 1152 | #define var_lookup(ls, e) \ | 1264 | static void var_assign(LexState *ls, ExpDesc *e) |
| 1153 | var_lookup_((ls)->fs, lex_str(ls), (e), 1) | 1265 | { |
| 1266 | if (e->k == VLOCAL || e->k == VUPVAL) { | ||
| 1267 | VarInfo *v = &ls->vstack[e->u.s.aux]; | ||
| 1268 | if ((v->info & VSTACK_CONST)) | ||
| 1269 | lj_lex_error(ls, 0, LJ_ERR_XCONSTA, strdata(strref(v->name))); | ||
| 1270 | } | ||
| 1271 | } | ||
| 1154 | 1272 | ||
| 1155 | /* -- Goto an label handling ---------------------------------------------- */ | 1273 | /* -- Goto and label handling --------------------------------------------- */ |
| 1156 | 1274 | ||
| 1157 | /* Add a new goto or label. */ | 1275 | /* Add a new goto or label. */ |
| 1158 | static MSize gola_new(LexState *ls, GCstr *name, uint8_t info, BCPos pc) | 1276 | static MSize gola_new(LexState *ls, GCstr *name, uint8_t info, BCPos pc) |
| @@ -1164,7 +1282,8 @@ static MSize gola_new(LexState *ls, GCstr *name, uint8_t info, BCPos pc) | |||
| 1164 | lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK); | 1282 | lj_lex_error(ls, 0, LJ_ERR_XLIMC, LJ_MAX_VSTACK); |
| 1165 | lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo); | 1283 | lj_mem_growvec(ls->L, ls->vstack, ls->sizevstack, LJ_MAX_VSTACK, VarInfo); |
| 1166 | } | 1284 | } |
| 1167 | lj_assertFS(name == NAME_BREAK || lj_tab_getstr(fs->kt, name) != NULL, | 1285 | lj_assertFS(name == NAME_BREAK || name == NAME_CONT || |
| 1286 | lj_tab_getstr(fs->kt, name) != NULL, | ||
| 1168 | "unanchored label name"); | 1287 | "unanchored label name"); |
| 1169 | /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ | 1288 | /* NOBARRIER: name is anchored in fs->kt and ls->vstack is not a GCobj. */ |
| 1170 | setgcref(ls->vstack[vtop].name, obj2gco(name)); | 1289 | setgcref(ls->vstack[vtop].name, obj2gco(name)); |
| @@ -1219,8 +1338,12 @@ static void gola_resolve(LexState *ls, FuncScope *bl, MSize idx) | |||
| 1219 | lj_assertLS((uintptr_t)name >= VARNAME__MAX, "expected goto name"); | 1338 | lj_assertLS((uintptr_t)name >= VARNAME__MAX, "expected goto name"); |
| 1220 | ls->linenumber = ls->fs->bcbase[vg->startpc].line; | 1339 | ls->linenumber = ls->fs->bcbase[vg->startpc].line; |
| 1221 | lj_assertLS(strref(vg->name) != NAME_BREAK, "unexpected break"); | 1340 | lj_assertLS(strref(vg->name) != NAME_BREAK, "unexpected break"); |
| 1222 | lj_lex_error(ls, 0, LJ_ERR_XGSCOPE, | 1341 | if (strref(vg->name) == NAME_CONT) { |
| 1223 | strdata(strref(vg->name)), strdata(name)); | 1342 | lj_lex_error(ls, 0, LJ_ERR_XCSCOPE, strdata(name)); |
| 1343 | } else { | ||
| 1344 | lj_lex_error(ls, 0, LJ_ERR_XGSCOPE, | ||
| 1345 | strdata(strref(vg->name)), strdata(name)); | ||
| 1346 | } | ||
| 1224 | } | 1347 | } |
| 1225 | gola_patch(ls, vg, vl); | 1348 | gola_patch(ls, vg, vl); |
| 1226 | } | 1349 | } |
| @@ -1244,8 +1367,10 @@ static void gola_fixup(LexState *ls, FuncScope *bl) | |||
| 1244 | gola_patch(ls, vg, v); | 1367 | gola_patch(ls, vg, v); |
| 1245 | } | 1368 | } |
| 1246 | } else if (gola_isgoto(v)) { | 1369 | } else if (gola_isgoto(v)) { |
| 1247 | if (bl->prev) { /* Propagate goto or break to outer scope. */ | 1370 | if (bl->prev) { /* Propagate goto, break or continue to outer scope. */ |
| 1248 | bl->prev->flags |= name == NAME_BREAK ? FSCOPE_BREAK : FSCOPE_GOLA; | 1371 | bl->prev->flags |= name == NAME_BREAK ? FSCOPE_BREAK : |
| 1372 | name == NAME_CONT ? FSCOPE_CONT : | ||
| 1373 | FSCOPE_GOLA; | ||
| 1249 | v->slot = bl->nactvar; | 1374 | v->slot = bl->nactvar; |
| 1250 | if ((bl->flags & FSCOPE_UPVAL)) | 1375 | if ((bl->flags & FSCOPE_UPVAL)) |
| 1251 | gola_close(ls, v); | 1376 | gola_close(ls, v); |
| @@ -1253,6 +1378,8 @@ static void gola_fixup(LexState *ls, FuncScope *bl) | |||
| 1253 | ls->linenumber = ls->fs->bcbase[v->startpc].line; | 1378 | ls->linenumber = ls->fs->bcbase[v->startpc].line; |
| 1254 | if (name == NAME_BREAK) | 1379 | if (name == NAME_BREAK) |
| 1255 | lj_lex_error(ls, 0, LJ_ERR_XBREAK); | 1380 | lj_lex_error(ls, 0, LJ_ERR_XBREAK); |
| 1381 | else if (name == NAME_CONT) | ||
| 1382 | lj_lex_error(ls, 0, LJ_ERR_XCONT); | ||
| 1256 | else | 1383 | else |
| 1257 | lj_lex_error(ls, 0, LJ_ERR_XLUNDEF, strdata(name)); | 1384 | lj_lex_error(ls, 0, LJ_ERR_XLUNDEF, strdata(name)); |
| 1258 | } | 1385 | } |
| @@ -1296,21 +1423,33 @@ static void fscope_end(FuncState *fs) | |||
| 1296 | lj_assertFS(bl->nactvar == fs->nactvar, "bad regalloc"); | 1423 | lj_assertFS(bl->nactvar == fs->nactvar, "bad regalloc"); |
| 1297 | if ((bl->flags & (FSCOPE_UPVAL|FSCOPE_NOCLOSE)) == FSCOPE_UPVAL) | 1424 | if ((bl->flags & (FSCOPE_UPVAL|FSCOPE_NOCLOSE)) == FSCOPE_UPVAL) |
| 1298 | bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); | 1425 | bcemit_AJ(fs, BC_UCLO, bl->nactvar, 0); |
| 1299 | if ((bl->flags & FSCOPE_BREAK)) { | 1426 | lj_assertFS((bl->flags & (FSCOPE_LOOP|FSCOPE_CONT)) != (FSCOPE_LOOP|FSCOPE_CONT), "dangling continue"); |
| 1300 | if ((bl->flags & FSCOPE_LOOP)) { | 1427 | if ((bl->flags & (FSCOPE_LOOP|FSCOPE_BREAK)) == (FSCOPE_LOOP|FSCOPE_BREAK)) { |
| 1301 | MSize idx = gola_new(ls, NAME_BREAK, VSTACK_LABEL, fs->pc); | 1428 | MSize idx; |
| 1302 | ls->vtop = idx; /* Drop break label immediately. */ | 1429 | bl->flags &= ~FSCOPE_BREAK; |
| 1303 | gola_resolve(ls, bl, idx); | 1430 | idx = gola_new(ls, NAME_BREAK, VSTACK_LABEL, fs->pc); |
| 1304 | } else { /* Need the fixup step to propagate the breaks. */ | 1431 | ls->vtop = idx; /* Drop break label immediately. */ |
| 1305 | gola_fixup(ls, bl); | 1432 | gola_resolve(ls, bl, idx); |
| 1306 | return; | 1433 | } |
| 1307 | } | 1434 | if ((bl->flags & (FSCOPE_GOLA|FSCOPE_BREAK|FSCOPE_CONT))) { |
| 1308 | } | ||
| 1309 | if ((bl->flags & FSCOPE_GOLA)) { | ||
| 1310 | gola_fixup(ls, bl); | 1435 | gola_fixup(ls, bl); |
| 1311 | } | 1436 | } |
| 1312 | } | 1437 | } |
| 1313 | 1438 | ||
| 1439 | /* Add continue label. */ | ||
| 1440 | static void fscope_continue(FuncState *fs, BCPos cont) | ||
| 1441 | { | ||
| 1442 | FuncScope *bl = fs->bl; | ||
| 1443 | if ((bl->flags & FSCOPE_CONT)) { | ||
| 1444 | LexState *ls = fs->ls; | ||
| 1445 | MSize idx; | ||
| 1446 | bl->flags &= ~FSCOPE_CONT; | ||
| 1447 | idx = gola_new(ls, NAME_CONT, VSTACK_LABEL, cont); | ||
| 1448 | ls->vtop = idx; /* Drop continue label immediately. */ | ||
| 1449 | gola_resolve(ls, bl, idx); | ||
| 1450 | } | ||
| 1451 | } | ||
| 1452 | |||
| 1314 | /* Mark scope as having an upvalue. */ | 1453 | /* Mark scope as having an upvalue. */ |
| 1315 | static void fscope_uvmark(FuncState *fs, BCReg level) | 1454 | static void fscope_uvmark(FuncState *fs, BCReg level) |
| 1316 | { | 1455 | { |
| @@ -1460,7 +1599,7 @@ static void fs_fixup_line(FuncState *fs, GCproto *pt, | |||
| 1460 | /* Prepare variable info for prototype. */ | 1599 | /* Prepare variable info for prototype. */ |
| 1461 | static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar) | 1600 | static size_t fs_prep_var(LexState *ls, FuncState *fs, size_t *ofsvar) |
| 1462 | { | 1601 | { |
| 1463 | VarInfo *vs =ls->vstack, *ve; | 1602 | VarInfo *vs = ls->vstack, *ve; |
| 1464 | MSize i, n; | 1603 | MSize i, n; |
| 1465 | BCPos lastpc; | 1604 | BCPos lastpc; |
| 1466 | lj_buf_reset(&ls->sb); /* Copy to temp. string buffer. */ | 1605 | lj_buf_reset(&ls->sb); /* Copy to temp. string buffer. */ |
| @@ -1633,7 +1772,7 @@ static void fs_init(LexState *ls, FuncState *fs) | |||
| 1633 | /* -- Expressions --------------------------------------------------------- */ | 1772 | /* -- Expressions --------------------------------------------------------- */ |
| 1634 | 1773 | ||
| 1635 | /* Forward declaration. */ | 1774 | /* Forward declaration. */ |
| 1636 | static void expr(LexState *ls, ExpDesc *v); | 1775 | static void expr(LexState *ls, ExpDesc *v, int nocolon); |
| 1637 | 1776 | ||
| 1638 | /* Return string expression. */ | 1777 | /* Return string expression. */ |
| 1639 | static void expr_str(LexState *ls, ExpDesc *e) | 1778 | static void expr_str(LexState *ls, ExpDesc *e) |
| @@ -1680,7 +1819,6 @@ static void expr_field(LexState *ls, ExpDesc *v) | |||
| 1680 | FuncState *fs = ls->fs; | 1819 | FuncState *fs = ls->fs; |
| 1681 | ExpDesc key; | 1820 | ExpDesc key; |
| 1682 | expr_toanyreg(fs, v); | 1821 | expr_toanyreg(fs, v); |
| 1683 | lj_lex_next(ls); /* Skip dot or colon. */ | ||
| 1684 | expr_str(ls, &key); | 1822 | expr_str(ls, &key); |
| 1685 | expr_index(fs, v, &key); | 1823 | expr_index(fs, v, &key); |
| 1686 | } | 1824 | } |
| @@ -1689,7 +1827,7 @@ static void expr_field(LexState *ls, ExpDesc *v) | |||
| 1689 | static void expr_bracket(LexState *ls, ExpDesc *v) | 1827 | static void expr_bracket(LexState *ls, ExpDesc *v) |
| 1690 | { | 1828 | { |
| 1691 | lj_lex_next(ls); /* Skip '['. */ | 1829 | lj_lex_next(ls); /* Skip '['. */ |
| 1692 | expr(ls, v); | 1830 | expr(ls, v, 0); |
| 1693 | expr_toval(ls->fs, v); | 1831 | expr_toval(ls->fs, v); |
| 1694 | lex_check(ls, ']'); | 1832 | lex_check(ls, ']'); |
| 1695 | } | 1833 | } |
| @@ -1731,8 +1869,7 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1731 | if (!expr_isk(&key)) expr_index(fs, e, &key); | 1869 | if (!expr_isk(&key)) expr_index(fs, e, &key); |
| 1732 | if (expr_isnumk(&key) && expr_numiszero(&key)) needarr = 1; else nhash++; | 1870 | if (expr_isnumk(&key) && expr_numiszero(&key)) needarr = 1; else nhash++; |
| 1733 | lex_check(ls, '='); | 1871 | lex_check(ls, '='); |
| 1734 | } else if ((ls->tok == TK_name || (!LJ_52 && ls->tok == TK_goto)) && | 1872 | } else if (lex_isname(ls->tok) && lj_lex_lookahead(ls) == '=') { |
| 1735 | lj_lex_lookahead(ls) == '=') { | ||
| 1736 | expr_str(ls, &key); | 1873 | expr_str(ls, &key); |
| 1737 | lex_check(ls, '='); | 1874 | lex_check(ls, '='); |
| 1738 | nhash++; | 1875 | nhash++; |
| @@ -1742,7 +1879,7 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1742 | narr++; | 1879 | narr++; |
| 1743 | needarr = vcall = 1; | 1880 | needarr = vcall = 1; |
| 1744 | } | 1881 | } |
| 1745 | expr(ls, &val); | 1882 | expr(ls, &val, 0); |
| 1746 | if (expr_isk(&key) && key.k != VKNIL && | 1883 | if (expr_isk(&key) && key.k != VKNIL && |
| 1747 | (key.k == VKSTR || expr_isk_nojump(&val))) { | 1884 | (key.k == VKSTR || expr_isk_nojump(&val))) { |
| 1748 | TValue k, *v; | 1885 | TValue k, *v; |
| @@ -1766,7 +1903,10 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1766 | } | 1903 | } |
| 1767 | } else { | 1904 | } else { |
| 1768 | nonconst: | 1905 | nonconst: |
| 1769 | if (val.k != VCALL) { expr_toanyreg(fs, &val); vcall = 0; } | 1906 | if (val.k != VCALL) { |
| 1907 | expr_toanyreg(fs, &val); | ||
| 1908 | vcall = 0; | ||
| 1909 | } | ||
| 1770 | if (expr_isk(&key)) expr_index(fs, e, &key); | 1910 | if (expr_isk(&key)) expr_index(fs, e, &key); |
| 1771 | bcemit_store(fs, e, &val); | 1911 | bcemit_store(fs, e, &val); |
| 1772 | } | 1912 | } |
| @@ -1808,16 +1948,17 @@ static void expr_table(LexState *ls, ExpDesc *e) | |||
| 1808 | } | 1948 | } |
| 1809 | 1949 | ||
| 1810 | /* Parse function parameters. */ | 1950 | /* Parse function parameters. */ |
| 1811 | static BCReg parse_params(LexState *ls, int needself) | 1951 | static BCReg parse_params(LexState *ls, int needself, |
| 1952 | LexToken before, LexToken after) | ||
| 1812 | { | 1953 | { |
| 1813 | FuncState *fs = ls->fs; | 1954 | FuncState *fs = ls->fs; |
| 1814 | BCReg nparams = 0; | 1955 | BCReg nparams = 0; |
| 1815 | lex_check(ls, '('); | 1956 | lex_check(ls, before); |
| 1816 | if (needself) | 1957 | if (needself) |
| 1817 | var_new_lit(ls, nparams++, "self"); | 1958 | var_new_lit(ls, nparams++, "self"); |
| 1818 | if (ls->tok != ')') { | 1959 | if (ls->tok != after) { |
| 1819 | do { | 1960 | do { |
| 1820 | if (ls->tok == TK_name || (!LJ_52 && ls->tok == TK_goto)) { | 1961 | if (lex_isname(ls->tok)) { |
| 1821 | var_new(ls, nparams++, lex_str(ls)); | 1962 | var_new(ls, nparams++, lex_str(ls)); |
| 1822 | } else if (ls->tok == TK_dots) { | 1963 | } else if (ls->tok == TK_dots) { |
| 1823 | lj_lex_next(ls); | 1964 | lj_lex_next(ls); |
| @@ -1831,54 +1972,96 @@ static BCReg parse_params(LexState *ls, int needself) | |||
| 1831 | var_add(ls, nparams); | 1972 | var_add(ls, nparams); |
| 1832 | lj_assertFS(fs->nactvar == nparams, "bad regalloc"); | 1973 | lj_assertFS(fs->nactvar == nparams, "bad regalloc"); |
| 1833 | bcreg_reserve(fs, nparams); | 1974 | bcreg_reserve(fs, nparams); |
| 1834 | lex_check(ls, ')'); | 1975 | lex_check(ls, after); |
| 1835 | return nparams; | 1976 | return nparams; |
| 1836 | } | 1977 | } |
| 1837 | 1978 | ||
| 1838 | /* Forward declaration. */ | 1979 | /* Forward declarations. */ |
| 1839 | static void parse_chunk(LexState *ls); | 1980 | static void parse_chunk(LexState *ls); |
| 1981 | static void parse_return(LexState *ls, int eflags); | ||
| 1840 | 1982 | ||
| 1841 | /* Parse body of a function. */ | 1983 | /* Begin a new function prototype. */ |
| 1842 | static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) | 1984 | static void proto_begin(FuncState *fs, BCLine line, BCReg nparams) |
| 1843 | { | 1985 | { |
| 1844 | FuncState fs, *pfs = ls->fs; | 1986 | FuncState *pfs = fs->prev; |
| 1845 | FuncScope bl; | 1987 | fs->linedefined = line; |
| 1846 | GCproto *pt; | 1988 | fs->numparams = (uint8_t)nparams; |
| 1847 | ptrdiff_t oldbase = pfs->bcbase - ls->bcstack; | 1989 | fs->bcbase = pfs->bcbase + pfs->pc; |
| 1848 | fs_init(ls, &fs); | 1990 | fs->bclim = pfs->bclim - pfs->pc; |
| 1849 | fscope_begin(&fs, &bl, 0); | 1991 | bcemit_AD(fs, BC_FUNCF, 0, 0); /* Placeholder. */ |
| 1850 | fs.linedefined = line; | 1992 | } |
| 1851 | fs.numparams = (uint8_t)parse_params(ls, needself); | 1993 | |
| 1852 | fs.bcbase = pfs->bcbase + pfs->pc; | 1994 | /* Finish a function prototype. */ |
| 1853 | fs.bclim = pfs->bclim - pfs->pc; | 1995 | static void proto_finish(LexState *ls, ExpDesc *e, ptrdiff_t oldbase) |
| 1854 | bcemit_AD(&fs, BC_FUNCF, 0, 0); /* Placeholder. */ | 1996 | { |
| 1855 | parse_chunk(ls); | 1997 | MSize flags = (ls->fs->flags & (PROTO_FFI|PROTO_BITOP)); |
| 1856 | if (ls->tok != TK_end) lex_match(ls, TK_end, TK_function, line); | 1998 | GCproto *pt = fs_finish(ls, (ls->lastline = ls->linenumber)); |
| 1857 | pt = fs_finish(ls, (ls->lastline = ls->linenumber)); | 1999 | FuncState *pfs = ls->fs; |
| 1858 | pfs->bcbase = ls->bcstack + oldbase; /* May have been reallocated. */ | 2000 | pfs->bcbase = ls->bcstack + oldbase; /* May have been reallocated. */ |
| 1859 | pfs->bclim = (BCPos)(ls->sizebcstack - oldbase); | 2001 | pfs->bclim = (BCPos)(ls->sizebcstack - oldbase); |
| 1860 | /* Store new prototype in the constant array of the parent. */ | 2002 | /* Store new prototype in the constant array of the parent. */ |
| 1861 | expr_init(e, VRELOCABLE, | 2003 | expr_init(e, VRELOCABLE, |
| 1862 | bcemit_AD(pfs, BC_FNEW, 0, const_gc(pfs, obj2gco(pt), LJ_TPROTO))); | 2004 | bcemit_AD(pfs, BC_FNEW, 0, const_gc(pfs, obj2gco(pt), LJ_TPROTO))); |
| 1863 | #if LJ_HASFFI | 2005 | pfs->flags |= (uint8_t)flags; /* Inherited flags. */ |
| 1864 | pfs->flags |= (fs.flags & PROTO_FFI); | ||
| 1865 | #endif | ||
| 1866 | if (!(pfs->flags & PROTO_CHILD)) { | 2006 | if (!(pfs->flags & PROTO_CHILD)) { |
| 1867 | if (pfs->flags & PROTO_HAS_RETURN) | 2007 | if (pfs->flags & PROTO_HAS_RETURN) |
| 1868 | pfs->flags |= PROTO_FIXUP_RETURN; | 2008 | pfs->flags |= PROTO_FIXUP_RETURN; |
| 1869 | pfs->flags |= PROTO_CHILD; | 2009 | pfs->flags |= PROTO_CHILD; |
| 1870 | } | 2010 | } |
| 2011 | } | ||
| 2012 | |||
| 2013 | /* Parse body of a function. */ | ||
| 2014 | static void parse_body(LexState *ls, ExpDesc *e, int needself, BCLine line) | ||
| 2015 | { | ||
| 2016 | ptrdiff_t oldbase = ls->fs->bcbase - ls->bcstack; | ||
| 2017 | FuncState fs; | ||
| 2018 | FuncScope bl; | ||
| 2019 | fs_init(ls, &fs); | ||
| 2020 | fscope_begin(&fs, &bl, 0); | ||
| 2021 | proto_begin(&fs, line, parse_params(ls, needself, '(', ')')); | ||
| 2022 | parse_chunk(ls); | ||
| 2023 | if (ls->tok != TK_end) lex_match(ls, TK_end, TK_function, line); | ||
| 2024 | proto_finish(ls, e, oldbase); | ||
| 1871 | lj_lex_next(ls); | 2025 | lj_lex_next(ls); |
| 1872 | } | 2026 | } |
| 1873 | 2027 | ||
| 2028 | /* Parse short function. */ | ||
| 2029 | static void parse_shortfunc(LexState *ls, ExpDesc *e, GCstr *name, | ||
| 2030 | int eflags, BCLine line) | ||
| 2031 | { | ||
| 2032 | ptrdiff_t oldbase = ls->fs->bcbase - ls->bcstack; | ||
| 2033 | FuncState fs; | ||
| 2034 | FuncScope bl; | ||
| 2035 | BCReg nparams = 0; | ||
| 2036 | fs_init(ls, &fs); | ||
| 2037 | fscope_begin(&fs, &bl, 0); | ||
| 2038 | if (name != NULL) { | ||
| 2039 | setboolV(lj_tab_setstr(ls->L, fs.kt, name), 1); /* Anchor in new proto. */ | ||
| 2040 | var_new(ls, nparams++, name); | ||
| 2041 | var_add(ls, nparams); | ||
| 2042 | bcreg_reserve(&fs, 1); | ||
| 2043 | } else if (!lex_opt(ls, TK_or_)) { | ||
| 2044 | nparams = parse_params(ls, 0, '|', '|'); | ||
| 2045 | } | ||
| 2046 | lex_check(ls, TK_arrow); | ||
| 2047 | proto_begin(&fs, line, nparams); | ||
| 2048 | if (lex_opt(ls, TK_do)) { | ||
| 2049 | parse_chunk(ls); | ||
| 2050 | if (!lex_opt(ls, TK_end)) lex_match(ls, TK_end, TK_do, line); | ||
| 2051 | } else { | ||
| 2052 | parse_return(ls, (eflags | EXPR_F_RET1)); | ||
| 2053 | } | ||
| 2054 | proto_finish(ls, e, oldbase); | ||
| 2055 | } | ||
| 2056 | |||
| 1874 | /* Parse expression list. Last expression is left open. */ | 2057 | /* Parse expression list. Last expression is left open. */ |
| 1875 | static BCReg expr_list(LexState *ls, ExpDesc *v) | 2058 | static BCReg expr_list(LexState *ls, ExpDesc *v) |
| 1876 | { | 2059 | { |
| 1877 | BCReg n = 1; | 2060 | BCReg n = 1; |
| 1878 | expr(ls, v); | 2061 | expr(ls, v, 0); |
| 1879 | while (lex_opt(ls, ',')) { | 2062 | while (lex_opt(ls, ',')) { |
| 1880 | expr_tonextreg(ls->fs, v); | 2063 | expr_tonextreg(ls->fs, v); |
| 1881 | expr(ls, v); | 2064 | expr(ls, v, 0); |
| 1882 | n++; | 2065 | n++; |
| 1883 | } | 2066 | } |
| 1884 | return n; | 2067 | return n; |
| @@ -1931,48 +2114,102 @@ static void parse_args(LexState *ls, ExpDesc *e) | |||
| 1931 | fs->freereg = base+1; /* Leave one result by default. */ | 2114 | fs->freereg = base+1; /* Leave one result by default. */ |
| 1932 | } | 2115 | } |
| 1933 | 2116 | ||
| 1934 | /* Parse primary expression. */ | 2117 | /* Parse primary expression with safe navigation. */ |
| 1935 | static void expr_primary(LexState *ls, ExpDesc *v) | 2118 | static BCPos expr_primary_nav(LexState *ls, ExpDesc *v, int eflags) |
| 1936 | { | 2119 | { |
| 1937 | FuncState *fs = ls->fs; | 2120 | FuncState *fs = ls->fs; |
| 2121 | BCPos xpc = NO_JMP; | ||
| 1938 | /* Parse prefix expression. */ | 2122 | /* Parse prefix expression. */ |
| 1939 | if (ls->tok == '(') { | 2123 | if (ls->tok == '(') { |
| 1940 | BCLine line = ls->linenumber; | 2124 | BCLine line = ls->linenumber; |
| 1941 | lj_lex_next(ls); | 2125 | lj_lex_next(ls); |
| 1942 | expr(ls, v); | 2126 | expr(ls, v, 0); /* Don't propagate eflags. */ |
| 1943 | lex_match(ls, ')', '(', line); | 2127 | lex_match(ls, ')', '(', line); |
| 1944 | expr_discharge(ls->fs, v); | 2128 | expr_discharge(ls->fs, v); |
| 1945 | } else if (ls->tok == TK_name || (!LJ_52 && ls->tok == TK_goto)) { | 2129 | } else if (lex_isname(ls->tok)) { |
| 1946 | var_lookup(ls, v); | 2130 | BCLine line = ls->linenumber; |
| 2131 | GCstr *name = lex_str(ls); | ||
| 2132 | if (!(eflags & EXPR_F_NORES) && ls->tok == TK_arrow) { | ||
| 2133 | parse_shortfunc(ls, v, name, eflags, line); | ||
| 2134 | return xpc; | ||
| 2135 | } | ||
| 2136 | var_lookup(ls, v, name); | ||
| 1947 | } else { | 2137 | } else { |
| 2138 | err: | ||
| 1948 | err_syntax(ls, LJ_ERR_XSYMBOL); | 2139 | err_syntax(ls, LJ_ERR_XSYMBOL); |
| 1949 | } | 2140 | } |
| 1950 | for (;;) { /* Parse multiple expression suffixes. */ | 2141 | for (;;) { /* Parse multiple expression suffixes. */ |
| 1951 | if (ls->tok == '.') { | 2142 | int nav = 0; |
| 1952 | expr_field(ls, v); | 2143 | if (!(eflags & EXPR_F_NONAV) && lex_opt(ls, TK_nav)) { |
| 1953 | } else if (ls->tok == '[') { | 2144 | nav = 1; |
| 2145 | expr_toanyreg(fs, v); | ||
| 2146 | bcemit_INS(fs, BCINS_AD(BC_ISEQP, v->u.s.info, VKNIL)); | ||
| 2147 | jmp_append(fs, &xpc, bcemit_jmp(fs)); | ||
| 2148 | } | ||
| 2149 | if (ls->tok == '[') { | ||
| 1954 | ExpDesc key; | 2150 | ExpDesc key; |
| 1955 | expr_toanyreg(fs, v); | 2151 | expr_toanyreg(fs, v); |
| 1956 | expr_bracket(ls, &key); | 2152 | expr_bracket(ls, &key); |
| 1957 | expr_index(fs, v, &key); | 2153 | expr_index(fs, v, &key); |
| 1958 | } else if (ls->tok == ':') { | 2154 | } else if (ls->tok == ':') { |
| 1959 | ExpDesc key; | 2155 | ExpDesc key; |
| 1960 | lj_lex_next(ls); | 2156 | if ((eflags & EXPR_F_NOCOLON)) { |
| 2157 | if (nav) goto err; | ||
| 2158 | break; | ||
| 2159 | } | ||
| 2160 | lj_lex_next(ls); /* Skip ':'. */ | ||
| 1961 | expr_str(ls, &key); | 2161 | expr_str(ls, &key); |
| 1962 | bcemit_method(fs, v, &key); | 2162 | bcemit_method(fs, v, &key); |
| 1963 | parse_args(ls, v); | 2163 | nav = 0; |
| 2164 | if (lex_opt(ls, TK_nav)) { | ||
| 2165 | nav = 1; | ||
| 2166 | bcemit_INS(fs, BCINS_AD(BC_ISEQP, v->u.s.info, VKNIL)); | ||
| 2167 | jmp_append(fs, &xpc, bcemit_jmp(fs)); | ||
| 2168 | } | ||
| 2169 | goto call; | ||
| 1964 | } else if (ls->tok == '(' || ls->tok == TK_string || ls->tok == '{') { | 2170 | } else if (ls->tok == '(' || ls->tok == TK_string || ls->tok == '{') { |
| 1965 | expr_tonextreg(fs, v); | 2171 | expr_tonextreg(fs, v); |
| 1966 | if (ls->fr2) bcreg_reserve(fs, 1); | 2172 | if (ls->fr2) bcreg_reserve(fs, 1); |
| 2173 | call: | ||
| 1967 | parse_args(ls, v); | 2174 | parse_args(ls, v); |
| 2175 | /* Keep nav VCALL if no suffix follows. */ | ||
| 2176 | if (nav && !(eflags & EXPR_F_NORES) && | ||
| 2177 | !(ls->tok == TK_nav || ls->tok == '[' || ls->tok == ':' || | ||
| 2178 | ls->tok == '(' || ls->tok == TK_string || ls->tok == '{' || | ||
| 2179 | ls->tok == '.')) break; | ||
| 2180 | } else if (nav || lex_opt(ls, '.')) { | ||
| 2181 | expr_field(ls, v); | ||
| 1968 | } else { | 2182 | } else { |
| 1969 | break; | 2183 | break; |
| 1970 | } | 2184 | } |
| 2185 | if (nav && !(eflags & EXPR_F_NORES)) { | ||
| 2186 | expr_tonextreg(fs, v); | ||
| 2187 | } | ||
| 2188 | } | ||
| 2189 | return xpc; | ||
| 2190 | } | ||
| 2191 | |||
| 2192 | /* Parse primary expression. */ | ||
| 2193 | static void expr_primary(LexState *ls, ExpDesc *v, int eflags) | ||
| 2194 | { | ||
| 2195 | BCPos xpc = expr_primary_nav(ls, v, eflags); | ||
| 2196 | if (xpc != NO_JMP) { | ||
| 2197 | FuncState *fs = ls->fs; | ||
| 2198 | BCPos around; | ||
| 2199 | around = bcemit_jmp(fs); | ||
| 2200 | jmp_tohere(fs, xpc); | ||
| 2201 | if (v->k == VCALL) { /* Change to VCALLNAV. Still points to CALL/CALLM. */ | ||
| 2202 | v->k = VCALLNAV; | ||
| 2203 | bcemit_AD(fs, BC_KPRI, v->u.s.aux, VKNIL); | ||
| 2204 | } else { | ||
| 2205 | bcemit_AD(fs, BC_KPRI, v->u.s.info, VKNIL); | ||
| 2206 | } | ||
| 2207 | jmp_tohere(fs, around); | ||
| 1971 | } | 2208 | } |
| 1972 | } | 2209 | } |
| 1973 | 2210 | ||
| 1974 | /* Parse simple expression. */ | 2211 | /* Parse simple expression. */ |
| 1975 | static void expr_simple(LexState *ls, ExpDesc *v) | 2212 | static void expr_simple(LexState *ls, ExpDesc *v, int eflags) |
| 1976 | { | 2213 | { |
| 1977 | switch (ls->tok) { | 2214 | switch (ls->tok) { |
| 1978 | case TK_number: | 2215 | case TK_number: |
| @@ -2009,8 +2246,11 @@ static void expr_simple(LexState *ls, ExpDesc *v) | |||
| 2009 | lj_lex_next(ls); | 2246 | lj_lex_next(ls); |
| 2010 | parse_body(ls, v, 0, ls->linenumber); | 2247 | parse_body(ls, v, 0, ls->linenumber); |
| 2011 | return; | 2248 | return; |
| 2249 | case '|': case TK_or_: | ||
| 2250 | parse_shortfunc(ls, v, NULL, eflags, ls->linenumber); | ||
| 2251 | return; | ||
| 2012 | default: | 2252 | default: |
| 2013 | expr_primary(ls, v); | 2253 | expr_primary(ls, v, eflags); |
| 2014 | return; | 2254 | return; |
| 2015 | } | 2255 | } |
| 2016 | lj_lex_next(ls); | 2256 | lj_lex_next(ls); |
| @@ -2035,15 +2275,22 @@ static BinOpr token2binop(LexToken tok) | |||
| 2035 | case '/': return OPR_DIV; | 2275 | case '/': return OPR_DIV; |
| 2036 | case '%': return OPR_MOD; | 2276 | case '%': return OPR_MOD; |
| 2037 | case '^': return OPR_POW; | 2277 | case '^': return OPR_POW; |
| 2278 | case '&': return OPR_BAND; | ||
| 2279 | case '|': return OPR_BOR; | ||
| 2280 | case '~': return OPR_BXOR; | ||
| 2281 | case TK_shl: return OPR_BSHL; | ||
| 2282 | case TK_shr: return OPR_BSHR; | ||
| 2283 | case TK_sar: return OPR_BSAR; | ||
| 2038 | case TK_concat: return OPR_CONCAT; | 2284 | case TK_concat: return OPR_CONCAT; |
| 2039 | case TK_ne: return OPR_NE; | 2285 | case TK_ne: case TK_ne_: return OPR_NE; |
| 2040 | case TK_eq: return OPR_EQ; | 2286 | case TK_eq: return OPR_EQ; |
| 2041 | case '<': return OPR_LT; | 2287 | case '<': return OPR_LT; |
| 2042 | case TK_le: return OPR_LE; | 2288 | case TK_le: return OPR_LE; |
| 2043 | case '>': return OPR_GT; | 2289 | case '>': return OPR_GT; |
| 2044 | case TK_ge: return OPR_GE; | 2290 | case TK_ge: return OPR_GE; |
| 2045 | case TK_and: return OPR_AND; | 2291 | case TK_and: case TK_and_: return OPR_AND; |
| 2046 | case TK_or: return OPR_OR; | 2292 | case TK_or: case TK_or_: return OPR_OR; |
| 2293 | case TK_coal: return OPR_COAL; | ||
| 2047 | default: return OPR_NOBINOPR; | 2294 | default: return OPR_NOBINOPR; |
| 2048 | } | 2295 | } |
| 2049 | } | 2296 | } |
| @@ -2053,69 +2300,91 @@ static const struct { | |||
| 2053 | uint8_t left; /* Left priority. */ | 2300 | uint8_t left; /* Left priority. */ |
| 2054 | uint8_t right; /* Right priority. */ | 2301 | uint8_t right; /* Right priority. */ |
| 2055 | } priority[] = { | 2302 | } priority[] = { |
| 2056 | {6,6}, {6,6}, {7,7}, {7,7}, {7,7}, /* ADD SUB MUL DIV MOD */ | 2303 | {10,10}, {10,10}, {11,11}, {11,11}, {11,11}, /* ADD SUB MUL DIV MOD */ |
| 2057 | {10,9}, {5,4}, /* POW CONCAT (right associative) */ | 2304 | {14,13}, /* POW (right associative) */ |
| 2305 | {6,6}, {4,4}, {5,5}, /* BAND BOR BXOR */ | ||
| 2306 | {7,7}, {7,7}, {7,7}, /* BSHL BSHR BSAR */ | ||
| 2307 | {9,8}, /* CONCAT (right associative) */ | ||
| 2058 | {3,3}, {3,3}, /* EQ NE */ | 2308 | {3,3}, {3,3}, /* EQ NE */ |
| 2059 | {3,3}, {3,3}, {3,3}, {3,3}, /* LT GE GT LE */ | 2309 | {3,3}, {3,3}, {3,3}, {3,3}, /* LT GE GT LE */ |
| 2060 | {2,2}, {1,1} /* AND OR */ | 2310 | {2,2}, {1,1}, {1,1} /* AND OR COAL */ |
| 2061 | }; | 2311 | }; |
| 2062 | 2312 | ||
| 2063 | #define UNARY_PRIORITY 8 /* Priority for unary operators. */ | 2313 | #define UNARY_PRIORITY 12 /* Priority for unary operators. */ |
| 2064 | 2314 | ||
| 2065 | /* Forward declaration. */ | 2315 | /* Forward declaration. */ |
| 2066 | static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit); | 2316 | static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit, int eflags); |
| 2067 | 2317 | ||
| 2068 | /* Parse unary expression. */ | 2318 | /* Parse unary expression. */ |
| 2069 | static void expr_unop(LexState *ls, ExpDesc *v) | 2319 | static void expr_unop(LexState *ls, ExpDesc *v, int eflags) |
| 2070 | { | 2320 | { |
| 2071 | BCOp op; | 2321 | BCOp op; |
| 2072 | if (ls->tok == TK_not) { | 2322 | if (ls->tok == TK_not || ls->tok == '!') { |
| 2073 | op = BC_NOT; | 2323 | op = BC_NOT; |
| 2074 | } else if (ls->tok == '-') { | 2324 | } else if (ls->tok == '-') { |
| 2075 | op = BC_UNM; | 2325 | op = BC_UNM; |
| 2076 | } else if (ls->tok == '#') { | 2326 | } else if (ls->tok == '#') { |
| 2077 | op = BC_LEN; | 2327 | op = BC_LEN; |
| 2328 | } else if (ls->tok == '~') { | ||
| 2329 | op = BC_BNOT; | ||
| 2078 | } else { | 2330 | } else { |
| 2079 | expr_simple(ls, v); | 2331 | expr_simple(ls, v, eflags); |
| 2080 | return; | 2332 | return; |
| 2081 | } | 2333 | } |
| 2082 | lj_lex_next(ls); | 2334 | lj_lex_next(ls); |
| 2083 | expr_binop(ls, v, UNARY_PRIORITY); | 2335 | expr_binop(ls, v, UNARY_PRIORITY, eflags); |
| 2084 | bcemit_unop(ls->fs, op, v); | 2336 | bcemit_unop(ls->fs, op, v); |
| 2085 | } | 2337 | } |
| 2086 | 2338 | ||
| 2087 | /* Parse binary expressions with priority higher than the limit. */ | 2339 | /* Parse binary expressions with priority higher than the limit. */ |
| 2088 | static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit) | 2340 | static BinOpr expr_binop(LexState *ls, ExpDesc *v, uint32_t limit, int eflags) |
| 2089 | { | 2341 | { |
| 2090 | BinOpr op; | 2342 | BinOpr opr; |
| 2091 | synlevel_begin(ls); | 2343 | synlevel_begin(ls); |
| 2092 | expr_unop(ls, v); | 2344 | expr_unop(ls, v, eflags); |
| 2093 | op = token2binop(ls->tok); | 2345 | opr = token2binop(ls->tok); |
| 2094 | while (op != OPR_NOBINOPR && priority[op].left > limit) { | 2346 | while (opr != OPR_NOBINOPR && priority[opr].left > limit) { |
| 2095 | ExpDesc v2; | 2347 | ExpDesc v2; |
| 2096 | BinOpr nextop; | 2348 | BinOpr nextop; |
| 2097 | lj_lex_next(ls); | 2349 | lj_lex_next(ls); |
| 2098 | bcemit_binop_left(ls->fs, op, v); | 2350 | bcemit_binop_left(ls->fs, opr, v); |
| 2099 | /* Parse binary expression with higher priority. */ | 2351 | /* Parse binary expression with higher priority. */ |
| 2100 | nextop = expr_binop(ls, &v2, priority[op].right); | 2352 | nextop = expr_binop(ls, &v2, priority[opr].right, eflags); |
| 2101 | bcemit_binop(ls->fs, op, v, &v2); | 2353 | bcemit_binop(ls->fs, opr, v, &v2); |
| 2102 | op = nextop; | 2354 | opr = nextop; |
| 2103 | } | 2355 | } |
| 2104 | synlevel_end(ls); | 2356 | synlevel_end(ls); |
| 2105 | return op; /* Return unconsumed binary operator (if any). */ | 2357 | return opr; /* Return unconsumed binary operator (if any). */ |
| 2106 | } | 2358 | } |
| 2107 | 2359 | ||
| 2108 | /* Parse expression. */ | 2360 | /* Parse expression. */ |
| 2109 | static void expr(LexState *ls, ExpDesc *v) | 2361 | static void expr(LexState *ls, ExpDesc *v, int eflags) |
| 2110 | { | 2362 | { |
| 2111 | expr_binop(ls, v, 0); /* Priority 0: parse whole expression. */ | 2363 | expr_binop(ls, v, 0, eflags); /* Priority 0: parse whole expression. */ |
| 2364 | if (lex_opt(ls, '?')) { /* Ternary ?: conditional operator. Right-assoc. */ | ||
| 2365 | FuncState *fs = ls->fs; | ||
| 2366 | BCPos escapelist = NO_JMP, cond; | ||
| 2367 | BCReg reg; | ||
| 2368 | bcemit_branch_t(fs, v); | ||
| 2369 | cond = v->f; | ||
| 2370 | expr(ls, v, EXPR_F_NOCOLON); /* Prevent method parsing. Use parentheses. */ | ||
| 2371 | expr_tonextreg(fs, v); | ||
| 2372 | reg = v->u.s.info; | ||
| 2373 | jmp_append(fs, &escapelist, bcemit_jmp(fs)); | ||
| 2374 | jmp_tohere(fs, cond); | ||
| 2375 | lex_check(ls, ':'); | ||
| 2376 | bcreg_free(fs, reg); | ||
| 2377 | expr(ls, v, 0); | ||
| 2378 | expr_tonextreg(fs, v); | ||
| 2379 | jmp_tohere(fs, escapelist); | ||
| 2380 | } | ||
| 2112 | } | 2381 | } |
| 2113 | 2382 | ||
| 2114 | /* Assign expression to the next register. */ | 2383 | /* Assign expression to the next register. */ |
| 2115 | static void expr_next(LexState *ls) | 2384 | static void expr_next(LexState *ls) |
| 2116 | { | 2385 | { |
| 2117 | ExpDesc e; | 2386 | ExpDesc e; |
| 2118 | expr(ls, &e); | 2387 | expr(ls, &e, 0); |
| 2119 | expr_tonextreg(ls->fs, &e); | 2388 | expr_tonextreg(ls->fs, &e); |
| 2120 | } | 2389 | } |
| 2121 | 2390 | ||
| @@ -2123,7 +2392,7 @@ static void expr_next(LexState *ls) | |||
| 2123 | static BCPos expr_cond(LexState *ls) | 2392 | static BCPos expr_cond(LexState *ls) |
| 2124 | { | 2393 | { |
| 2125 | ExpDesc v; | 2394 | ExpDesc v; |
| 2126 | expr(ls, &v); | 2395 | expr(ls, &v, 0); |
| 2127 | if (v.k == VKNIL) v.k = VKFALSE; | 2396 | if (v.k == VKNIL) v.k = VKFALSE; |
| 2128 | bcemit_branch_t(ls->fs, &v); | 2397 | bcemit_branch_t(ls->fs, &v); |
| 2129 | return v.f; | 2398 | return v.f; |
| @@ -2137,6 +2406,44 @@ typedef struct LHSVarList { | |||
| 2137 | struct LHSVarList *prev; /* Link to previous LHS variable. */ | 2406 | struct LHSVarList *prev; /* Link to previous LHS variable. */ |
| 2138 | } LHSVarList; | 2407 | } LHSVarList; |
| 2139 | 2408 | ||
| 2409 | /* Parse compound assignment. */ | ||
| 2410 | static int parse_compound(LexState *ls, ExpDesc *e) | ||
| 2411 | { | ||
| 2412 | FuncState *fs; | ||
| 2413 | ExpDesc estore, v; | ||
| 2414 | BinOpr opr; | ||
| 2415 | if (!(e->k >= VLOCAL && e->k <= VINDEXED)) return 0; | ||
| 2416 | opr = token2binop(ls->tok); | ||
| 2417 | /* '^=' aka exponentiation assignment is deliberately omitted to avoid | ||
| 2418 | ** confusion with xor assignment in other computer languages. | ||
| 2419 | ** Use 'a ~= b' for xor assignment. The unequal operator is only valid | ||
| 2420 | ** in expression contexts and assignments are statements. | ||
| 2421 | */ | ||
| 2422 | if (opr > OPR_NE || opr == OPR_POW) return 0; /* ORDER OPR */ | ||
| 2423 | var_assign(ls, e); | ||
| 2424 | if (opr == OPR_NE) { | ||
| 2425 | if (ls->tok != TK_ne) lj_lex_error(ls, '!', LJ_ERR_XTOKEN, "="); | ||
| 2426 | opr = OPR_BXOR; | ||
| 2427 | } else { /* Can't use lex_check() here. Only allow '+=', not '+ ='. */ | ||
| 2428 | if (ls->c != '=') err_token(ls, '='); | ||
| 2429 | lj_lex_next(ls); /* Skip operator. */ | ||
| 2430 | } | ||
| 2431 | lj_lex_next(ls); /* Skip '=' or '~=' aka TOK_ne. */ | ||
| 2432 | fs = ls->fs; | ||
| 2433 | estore = *e; | ||
| 2434 | if (e->k == VINDEXED) { /* Preserve the base and key for the store. */ | ||
| 2435 | BCReg freg = fs->freereg; | ||
| 2436 | expr_discharge(fs, e); | ||
| 2437 | fs->freereg = freg; /* Undo bcreg_free of info and/or aux. */ | ||
| 2438 | } | ||
| 2439 | if (opr == OPR_CONCAT) expr_tonextreg(fs, e); else expr_toanyreg(fs, e); | ||
| 2440 | expr(ls, &v, 0); | ||
| 2441 | bcemit_binop(fs, opr, e, &v); | ||
| 2442 | bcemit_store(fs, &estore, e); | ||
| 2443 | /* Don't bother to free VINDEXED info+aux. Done by parse_chunk(). */ | ||
| 2444 | return 1; | ||
| 2445 | } | ||
| 2446 | |||
| 2140 | /* Eliminate write-after-read hazards for local variable assignment. */ | 2447 | /* Eliminate write-after-read hazards for local variable assignment. */ |
| 2141 | static void assign_hazard(LexState *ls, LHSVarList *lh, const ExpDesc *v) | 2448 | static void assign_hazard(LexState *ls, LHSVarList *lh, const ExpDesc *v) |
| 2142 | { | 2449 | { |
| @@ -2167,11 +2474,23 @@ static void assign_adjust(LexState *ls, BCReg nvars, BCReg nexps, ExpDesc *e) | |||
| 2167 | { | 2474 | { |
| 2168 | FuncState *fs = ls->fs; | 2475 | FuncState *fs = ls->fs; |
| 2169 | int32_t extra = (int32_t)nvars - (int32_t)nexps; | 2476 | int32_t extra = (int32_t)nvars - (int32_t)nexps; |
| 2170 | if (e->k == VCALL) { | 2477 | if (e->k == VCALL || e->k == VCALLNAV) { |
| 2478 | BCInsLine *ilp = &fs->bcbase[e->u.s.info]; | ||
| 2171 | extra++; /* Compensate for the VCALL itself. */ | 2479 | extra++; /* Compensate for the VCALL itself. */ |
| 2172 | if (extra < 0) extra = 0; | 2480 | if (extra < 0) extra = 0; |
| 2173 | setbc_b(bcptr(fs, e), extra+1); /* Fixup call results. */ | 2481 | setbc_b(&ilp->ins, extra+1); /* Fixup call results. */ |
| 2174 | if (extra > 1) bcreg_reserve(fs, (BCReg)extra-1); | 2482 | if (extra > 1) bcreg_reserve(fs, (BCReg)extra-1); |
| 2483 | if (e->k == VCALLNAV) { /* Safe navigation result. */ | ||
| 2484 | BCPos base = e->u.s.aux; | ||
| 2485 | lj_assertFS((bc_op(ilp[0].ins) == BC_CALL || | ||
| 2486 | bc_op(ilp[0].ins) == BC_CALLM) && | ||
| 2487 | bc_op(ilp[1].ins) == BC_JMP && | ||
| 2488 | bc_op(ilp[2].ins) == BC_KPRI, | ||
| 2489 | "expected CALL|CALLM, JMP, KPRI inside safe navigation"); | ||
| 2490 | setbc_a(&ilp[1].ins, base + extra); /* Fixup JMP nactvar. */ | ||
| 2491 | if (extra > 1) /* Need more nils. Case extra == 0 is harmless. */ | ||
| 2492 | ilp[2].ins = BCINS_AD(BC_KNIL, base, base + extra-1); | ||
| 2493 | } | ||
| 2175 | } else { | 2494 | } else { |
| 2176 | if (e->k != VVOID) | 2495 | if (e->k != VVOID) |
| 2177 | expr_tonextreg(fs, e); /* Close last expression. */ | 2496 | expr_tonextreg(fs, e); /* Close last expression. */ |
| @@ -2190,10 +2509,11 @@ static void parse_assignment(LexState *ls, LHSVarList *lh, BCReg nvars) | |||
| 2190 | { | 2509 | { |
| 2191 | ExpDesc e; | 2510 | ExpDesc e; |
| 2192 | checkcond(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, LJ_ERR_XSYNTAX); | 2511 | checkcond(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXED, LJ_ERR_XSYNTAX); |
| 2512 | var_assign(ls, &lh->v); | ||
| 2193 | if (lex_opt(ls, ',')) { /* Collect LHS list and recurse upwards. */ | 2513 | if (lex_opt(ls, ',')) { /* Collect LHS list and recurse upwards. */ |
| 2194 | LHSVarList vl; | 2514 | LHSVarList vl; |
| 2195 | vl.prev = lh; | 2515 | vl.prev = lh; |
| 2196 | expr_primary(ls, &vl.v); | 2516 | expr_primary(ls, &vl.v, EXPR_F_NONAV); |
| 2197 | if (vl.v.k == VLOCAL) | 2517 | if (vl.v.k == VLOCAL) |
| 2198 | assign_hazard(ls, lh, &vl.v); | 2518 | assign_hazard(ls, lh, &vl.v); |
| 2199 | checklimit(ls->fs, ls->level + nvars, LJ_MAX_XLEVEL, "variable names"); | 2519 | checklimit(ls->fs, ls->level + nvars, LJ_MAX_XLEVEL, "variable names"); |
| @@ -2208,6 +2528,11 @@ static void parse_assignment(LexState *ls, LHSVarList *lh, BCReg nvars) | |||
| 2208 | ls->fs->freereg--; | 2528 | ls->fs->freereg--; |
| 2209 | e.k = VRELOCABLE; | 2529 | e.k = VRELOCABLE; |
| 2210 | } else { /* Multiple call results. */ | 2530 | } else { /* Multiple call results. */ |
| 2531 | lj_assertLS(bc_op(*bcptr(ls->fs, &e)) == BC_CALL || | ||
| 2532 | bc_op(*bcptr(ls->fs, &e)) == BC_CALLM || | ||
| 2533 | bc_op(*bcptr(ls->fs, &e)) == BC_KPRI, | ||
| 2534 | "unexpected call expression bytecode %d in assignment", | ||
| 2535 | bc_op(*bcptr(ls->fs, &e))); | ||
| 2211 | e.u.s.info = e.u.s.aux; /* Base of call is not relocatable. */ | 2536 | e.u.s.info = e.u.s.aux; /* Base of call is not relocatable. */ |
| 2212 | e.k = VNONRELOC; | 2537 | e.k = VNONRELOC; |
| 2213 | } | 2538 | } |
| @@ -2227,22 +2552,30 @@ static void parse_call_assign(LexState *ls) | |||
| 2227 | { | 2552 | { |
| 2228 | FuncState *fs = ls->fs; | 2553 | FuncState *fs = ls->fs; |
| 2229 | LHSVarList vl; | 2554 | LHSVarList vl; |
| 2230 | expr_primary(ls, &vl.v); | 2555 | BCReg xpc = expr_primary_nav(ls, &vl.v, EXPR_F_NORES); |
| 2231 | if (vl.v.k == VCALL) { /* Function call statement. */ | 2556 | if (vl.v.k == VCALL) { /* Function call statement. */ |
| 2232 | setbc_b(bcptr(fs, &vl.v), 1); /* No results. */ | 2557 | setbc_b(bcptr(fs, &vl.v), 1); /* No results. */ |
| 2233 | } else { /* Start of an assignment. */ | 2558 | } else { /* Start of an assignment. */ |
| 2234 | vl.prev = NULL; | 2559 | lj_assertFS(vl.v.k != VCALLNAV, "unexpected VCALLNAV in statement"); |
| 2235 | parse_assignment(ls, &vl, 1); | 2560 | /* Safe navigation is incompatible with parallel assignment. */ |
| 2561 | checkcond(ls, xpc == NO_JMP || ls->tok != ',', LJ_ERR_XSYNTAX); | ||
| 2562 | if (!parse_compound(ls, &vl.v)) { | ||
| 2563 | vl.prev = NULL; | ||
| 2564 | parse_assignment(ls, &vl, 1); | ||
| 2565 | } | ||
| 2236 | } | 2566 | } |
| 2567 | if (xpc != NO_JMP) jmp_tohere(fs, xpc); | ||
| 2237 | } | 2568 | } |
| 2238 | 2569 | ||
| 2239 | /* Parse 'local' statement. */ | 2570 | /* Parse 'local' or 'const' statement. */ |
| 2240 | static void parse_local(LexState *ls) | 2571 | static void parse_local(LexState *ls, int vinfo) |
| 2241 | { | 2572 | { |
| 2573 | lj_lex_next(ls); /* Skip local or const. */ | ||
| 2242 | if (lex_opt(ls, TK_function)) { /* Local function declaration. */ | 2574 | if (lex_opt(ls, TK_function)) { /* Local function declaration. */ |
| 2243 | ExpDesc v, b; | 2575 | ExpDesc v, b; |
| 2244 | FuncState *fs = ls->fs; | 2576 | FuncState *fs = ls->fs; |
| 2245 | var_new(ls, 0, lex_str(ls)); | 2577 | MSize vidx = var_new(ls, 0, lex_str(ls)); |
| 2578 | ls->vstack[vidx].info = (uint8_t)vinfo; | ||
| 2246 | expr_init(&v, VLOCAL, fs->freereg); | 2579 | expr_init(&v, VLOCAL, fs->freereg); |
| 2247 | v.u.s.aux = fs->varmap[fs->freereg]; | 2580 | v.u.s.aux = fs->varmap[fs->freereg]; |
| 2248 | bcreg_reserve(fs, 1); | 2581 | bcreg_reserve(fs, 1); |
| @@ -2256,9 +2589,23 @@ static void parse_local(LexState *ls) | |||
| 2256 | } else { /* Local variable declaration. */ | 2589 | } else { /* Local variable declaration. */ |
| 2257 | ExpDesc e; | 2590 | ExpDesc e; |
| 2258 | BCReg nexps, nvars = 0; | 2591 | BCReg nexps, nvars = 0; |
| 2259 | do { /* Collect LHS. */ | 2592 | if (vinfo) { /* Multiple consts need to be checked against each other. */ |
| 2260 | var_new(ls, nvars++, lex_str(ls)); | 2593 | VarIndex vhsave[LJ_VINDEX_HSIZE]; |
| 2261 | } while (lex_opt(ls, ',')); | 2594 | memcpy(vhsave, ls->vhash, sizeof(vhsave)); |
| 2595 | do { /* Collect LHS. */ | ||
| 2596 | MSize vidx = var_new(ls, nvars++, lex_str(ls)); | ||
| 2597 | VarInfo *v = &ls->vstack[vidx]; | ||
| 2598 | VarHash hash = var_hash(strref(v->name)); | ||
| 2599 | v->prev = ls->vhash[hash]; /* Temporarily add to hash. */ | ||
| 2600 | ls->vhash[hash] = vidx; | ||
| 2601 | v->info = (uint8_t)vinfo; | ||
| 2602 | } while (lex_opt(ls, ',')); | ||
| 2603 | memcpy(ls->vhash, vhsave, sizeof(vhsave)); /* Restore hash anchors. */ | ||
| 2604 | } else { | ||
| 2605 | do { /* Collect LHS. */ | ||
| 2606 | var_new(ls, nvars++, lex_str(ls)); | ||
| 2607 | } while (lex_opt(ls, ',')); | ||
| 2608 | } | ||
| 2262 | if (lex_opt(ls, '=')) { /* Optional RHS. */ | 2609 | if (lex_opt(ls, '=')) { /* Optional RHS. */ |
| 2263 | nexps = expr_list(ls, &e); | 2610 | nexps = expr_list(ls, &e); |
| 2264 | } else { /* Or implicitly set to nil. */ | 2611 | } else { /* Or implicitly set to nil. */ |
| @@ -2277,14 +2624,14 @@ static void parse_func(LexState *ls, BCLine line) | |||
| 2277 | ExpDesc v, b; | 2624 | ExpDesc v, b; |
| 2278 | int needself = 0; | 2625 | int needself = 0; |
| 2279 | lj_lex_next(ls); /* Skip 'function'. */ | 2626 | lj_lex_next(ls); /* Skip 'function'. */ |
| 2280 | /* Parse function name. */ | 2627 | var_lookup(ls, &v, lex_str(ls)); /* Parse function name. */ |
| 2281 | var_lookup(ls, &v); | 2628 | while (lex_opt(ls, '.')) /* Multiple dot-separated fields. */ |
| 2282 | while (ls->tok == '.') /* Multiple dot-separated fields. */ | ||
| 2283 | expr_field(ls, &v); | 2629 | expr_field(ls, &v); |
| 2284 | if (ls->tok == ':') { /* Optional colon to signify method call. */ | 2630 | if (lex_opt(ls, ':')) { /* Optional colon to signify method call. */ |
| 2285 | needself = 1; | 2631 | needself = 1; |
| 2286 | expr_field(ls, &v); | 2632 | expr_field(ls, &v); |
| 2287 | } | 2633 | } |
| 2634 | var_assign(ls, &v); | ||
| 2288 | parse_body(ls, &b, needself, line); | 2635 | parse_body(ls, &b, needself, line); |
| 2289 | fs = ls->fs; | 2636 | fs = ls->fs; |
| 2290 | bcemit_store(fs, &v, &b); | 2637 | bcemit_store(fs, &v, &b); |
| @@ -2305,19 +2652,25 @@ static int parse_isend(LexToken tok) | |||
| 2305 | } | 2652 | } |
| 2306 | 2653 | ||
| 2307 | /* Parse 'return' statement. */ | 2654 | /* Parse 'return' statement. */ |
| 2308 | static void parse_return(LexState *ls) | 2655 | static void parse_return(LexState *ls, int eflags) |
| 2309 | { | 2656 | { |
| 2310 | BCIns ins; | 2657 | BCIns ins; |
| 2311 | FuncState *fs = ls->fs; | 2658 | FuncState *fs = ls->fs; |
| 2312 | lj_lex_next(ls); /* Skip 'return'. */ | ||
| 2313 | fs->flags |= PROTO_HAS_RETURN; | 2659 | fs->flags |= PROTO_HAS_RETURN; |
| 2314 | if (parse_isend(ls->tok) || ls->tok == ';') { /* Bare return. */ | 2660 | if (!(eflags & EXPR_F_RET1) && (parse_isend(ls->tok) || ls->tok == ';')) { |
| 2315 | ins = BCINS_AD(BC_RET0, 0, 1); | 2661 | ins = BCINS_AD(BC_RET0, 0, 1); /* Bare return. */ |
| 2316 | } else { /* Return with one or more values. */ | 2662 | } else { /* Return with one or more values. */ |
| 2317 | ExpDesc e; /* Receives the _last_ expression in the list. */ | 2663 | ExpDesc e; /* Receives the _last_ expression in the list. */ |
| 2318 | BCReg nret = expr_list(ls, &e); | 2664 | BCReg nret; |
| 2665 | if ((eflags & EXPR_F_RET1)) { | ||
| 2666 | expr(ls, &e, eflags); | ||
| 2667 | nret = 1; | ||
| 2668 | } else { | ||
| 2669 | nret = expr_list(ls, &e); | ||
| 2670 | } | ||
| 2319 | if (nret == 1) { /* Return one result. */ | 2671 | if (nret == 1) { /* Return one result. */ |
| 2320 | if (e.k == VCALL) { /* Check for tail call. */ | 2672 | /* Check for tail call. */ |
| 2673 | if (e.k == VCALL) { | ||
| 2321 | #ifdef LUAJIT_DISABLE_TAILCALL | 2674 | #ifdef LUAJIT_DISABLE_TAILCALL |
| 2322 | goto notailcall; | 2675 | goto notailcall; |
| 2323 | #else | 2676 | #else |
| @@ -2331,7 +2684,8 @@ static void parse_return(LexState *ls) | |||
| 2331 | ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); | 2684 | ins = BCINS_AD(BC_RET1, expr_toanyreg(fs, &e), 2); |
| 2332 | } | 2685 | } |
| 2333 | } else { | 2686 | } else { |
| 2334 | if (e.k == VCALL) { /* Append all results from a call. */ | 2687 | if (e.k == VCALL) { |
| 2688 | /* Append all results from a call. */ | ||
| 2335 | notailcall: | 2689 | notailcall: |
| 2336 | setbc_b(bcptr(fs, &e), 0); | 2690 | setbc_b(bcptr(fs, &e), 0); |
| 2337 | ins = BCINS_AD(BC_RETM, fs->nactvar, e.u.s.aux - fs->nactvar); | 2691 | ins = BCINS_AD(BC_RETM, fs->nactvar, e.u.s.aux - fs->nactvar); |
| @@ -2353,6 +2707,13 @@ static void parse_break(LexState *ls) | |||
| 2353 | gola_new(ls, NAME_BREAK, VSTACK_GOTO, bcemit_jmp(ls->fs)); | 2707 | gola_new(ls, NAME_BREAK, VSTACK_GOTO, bcemit_jmp(ls->fs)); |
| 2354 | } | 2708 | } |
| 2355 | 2709 | ||
| 2710 | /* Parse 'continue' statement. */ | ||
| 2711 | static void parse_continue(LexState *ls) | ||
| 2712 | { | ||
| 2713 | ls->fs->bl->flags |= FSCOPE_CONT; | ||
| 2714 | gola_new(ls, NAME_CONT, VSTACK_GOTO, bcemit_jmp(ls->fs)); | ||
| 2715 | } | ||
| 2716 | |||
| 2356 | /* Parse 'goto' statement. */ | 2717 | /* Parse 'goto' statement. */ |
| 2357 | static void parse_goto(LexState *ls) | 2718 | static void parse_goto(LexState *ls) |
| 2358 | { | 2719 | { |
| @@ -2424,6 +2785,7 @@ static void parse_while(LexState *ls, BCLine line) | |||
| 2424 | parse_block(ls); | 2785 | parse_block(ls); |
| 2425 | jmp_patch(fs, bcemit_jmp(fs), start); | 2786 | jmp_patch(fs, bcemit_jmp(fs), start); |
| 2426 | lex_match(ls, TK_end, TK_while, line); | 2787 | lex_match(ls, TK_end, TK_while, line); |
| 2788 | fscope_continue(fs, start); | ||
| 2427 | fscope_end(fs); | 2789 | fscope_end(fs); |
| 2428 | jmp_tohere(fs, condexit); | 2790 | jmp_tohere(fs, condexit); |
| 2429 | jmp_patchins(fs, loop, fs->pc); | 2791 | jmp_patchins(fs, loop, fs->pc); |
| @@ -2442,6 +2804,7 @@ static void parse_repeat(LexState *ls, BCLine line) | |||
| 2442 | bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); | 2804 | bcemit_AD(fs, BC_LOOP, fs->nactvar, 0); |
| 2443 | parse_chunk(ls); | 2805 | parse_chunk(ls); |
| 2444 | lex_match(ls, TK_until, TK_repeat, line); | 2806 | lex_match(ls, TK_until, TK_repeat, line); |
| 2807 | fscope_continue(fs, fs->pc); | ||
| 2445 | condexit = expr_cond(ls); /* Parse condition (still inside inner scope). */ | 2808 | condexit = expr_cond(ls); /* Parse condition (still inside inner scope). */ |
| 2446 | if (!(bl2.flags & FSCOPE_UPVAL)) { /* No upvalues? Just end inner scope. */ | 2809 | if (!(bl2.flags & FSCOPE_UPVAL)) { /* No upvalues? Just end inner scope. */ |
| 2447 | fscope_end(fs); | 2810 | fscope_end(fs); |
| @@ -2487,6 +2850,7 @@ static void parse_for_num(LexState *ls, GCstr *varname, BCLine line) | |||
| 2487 | bcreg_reserve(fs, 1); | 2850 | bcreg_reserve(fs, 1); |
| 2488 | parse_block(ls); | 2851 | parse_block(ls); |
| 2489 | fscope_end(fs); | 2852 | fscope_end(fs); |
| 2853 | fscope_continue(fs, fs->pc); | ||
| 2490 | /* Perform loop inversion. Loop control instructions are at the end. */ | 2854 | /* Perform loop inversion. Loop control instructions are at the end. */ |
| 2491 | loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP); | 2855 | loopend = bcemit_AJ(fs, BC_FORL, base, NO_JMP); |
| 2492 | fs->bcbase[loopend].line = line; /* Fix line for control ins. */ | 2856 | fs->bcbase[loopend].line = line; /* Fix line for control ins. */ |
| @@ -2562,6 +2926,7 @@ static void parse_for_iter(LexState *ls, GCstr *indexname) | |||
| 2562 | fscope_end(fs); | 2926 | fscope_end(fs); |
| 2563 | /* Perform loop inversion. Loop control instructions are at the end. */ | 2927 | /* Perform loop inversion. Loop control instructions are at the end. */ |
| 2564 | jmp_patchins(fs, loop, fs->pc); | 2928 | jmp_patchins(fs, loop, fs->pc); |
| 2929 | fscope_continue(fs, fs->pc); | ||
| 2565 | bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1); | 2930 | bcemit_ABC(fs, isnext ? BC_ITERN : BC_ITERC, base, nvars-3+1, 2+1); |
| 2566 | loopend = bcemit_AJ(fs, BC_ITERL, base, NO_JMP); | 2931 | loopend = bcemit_AJ(fs, BC_ITERL, base, NO_JMP); |
| 2567 | fs->bcbase[loopend-1].line = line; /* Fix line for control ins. */ | 2932 | fs->bcbase[loopend-1].line = line; /* Fix line for control ins. */ |
| @@ -2651,16 +3016,28 @@ static int parse_stmt(LexState *ls) | |||
| 2651 | parse_func(ls, line); | 3016 | parse_func(ls, line); |
| 2652 | break; | 3017 | break; |
| 2653 | case TK_local: | 3018 | case TK_local: |
| 2654 | lj_lex_next(ls); | 3019 | parse_local(ls, 0); |
| 2655 | parse_local(ls); | 3020 | break; |
| 3021 | case TK_const: { | ||
| 3022 | LexToken tokx = lj_lex_lookahead(ls); | ||
| 3023 | if (!(lex_isname(tokx) || tokx == TK_function)) | ||
| 3024 | goto assign; /* Soft keyword. */ | ||
| 3025 | parse_local(ls, VSTACK_CONST); | ||
| 2656 | break; | 3026 | break; |
| 3027 | } | ||
| 2657 | case TK_return: | 3028 | case TK_return: |
| 2658 | parse_return(ls); | 3029 | lj_lex_next(ls); |
| 3030 | parse_return(ls, 0); | ||
| 2659 | return 1; /* Must be last. */ | 3031 | return 1; /* Must be last. */ |
| 2660 | case TK_break: | 3032 | case TK_break: |
| 2661 | lj_lex_next(ls); | 3033 | lj_lex_next(ls); |
| 2662 | parse_break(ls); | 3034 | parse_break(ls); |
| 2663 | return !LJ_52; /* Must be last in Lua 5.1. */ | 3035 | return !LJ_52; /* Must be last in Lua 5.1. */ |
| 3036 | case TK_continue: | ||
| 3037 | if (!parse_isend(lj_lex_lookahead(ls))) goto assign; /* Soft keyword. */ | ||
| 3038 | lj_lex_next(ls); | ||
| 3039 | parse_continue(ls); | ||
| 3040 | return 1; /* Must be last. */ | ||
| 2664 | #if LJ_52 | 3041 | #if LJ_52 |
| 2665 | case ';': | 3042 | case ';': |
| 2666 | lj_lex_next(ls); | 3043 | lj_lex_next(ls); |
| @@ -2670,13 +3047,14 @@ static int parse_stmt(LexState *ls) | |||
| 2670 | parse_label(ls); | 3047 | parse_label(ls); |
| 2671 | break; | 3048 | break; |
| 2672 | case TK_goto: | 3049 | case TK_goto: |
| 2673 | if (LJ_52 || lj_lex_lookahead(ls) == TK_name) { | 3050 | if (LJ_52 || lex_isname(lj_lex_lookahead(ls))) { /* 5.1 soft keyword. */ |
| 2674 | lj_lex_next(ls); | 3051 | lj_lex_next(ls); |
| 2675 | parse_goto(ls); | 3052 | parse_goto(ls); |
| 2676 | break; | 3053 | break; |
| 2677 | } | 3054 | } |
| 2678 | /* fallthrough */ | 3055 | /* fallthrough */ |
| 2679 | default: | 3056 | default: |
| 3057 | assign: | ||
| 2680 | parse_call_assign(ls); | 3058 | parse_call_assign(ls); |
| 2681 | break; | 3059 | break; |
| 2682 | } | 3060 | } |
| @@ -2714,6 +3092,7 @@ GCproto *lj_parse(LexState *ls) | |||
| 2714 | setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */ | 3092 | setstrV(L, L->top, ls->chunkname); /* Anchor chunkname string. */ |
| 2715 | incr_top(L); | 3093 | incr_top(L); |
| 2716 | ls->level = 0; | 3094 | ls->level = 0; |
| 3095 | memset(ls->vhash, 0xff, sizeof(ls->vhash)); | ||
| 2717 | fs_init(ls, &fs); | 3096 | fs_init(ls, &fs); |
| 2718 | fs.linedefined = 0; | 3097 | fs.linedefined = 0; |
| 2719 | fs.numparams = 0; | 3098 | fs.numparams = 0; |
diff --git a/src/lj_record.c b/src/lj_record.c index 8a123a61f..6afe2035b 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "lj_frame.h" | 17 | #include "lj_frame.h" |
| 18 | #if LJ_HASFFI | 18 | #if LJ_HASFFI |
| 19 | #include "lj_ctype.h" | 19 | #include "lj_ctype.h" |
| 20 | #include "lj_crecord.h" | ||
| 20 | #endif | 21 | #endif |
| 21 | #include "lj_bc.h" | 22 | #include "lj_bc.h" |
| 22 | #include "lj_ff.h" | 23 | #include "lj_ff.h" |
| @@ -2505,6 +2506,45 @@ void lj_record_ins(jit_State *J) | |||
| 2505 | rc = rec_mm_arith(J, &ix, MM_pow); | 2506 | rc = rec_mm_arith(J, &ix, MM_pow); |
| 2506 | break; | 2507 | break; |
| 2507 | 2508 | ||
| 2509 | /* -- Bit operators ----------------------------------------------------- */ | ||
| 2510 | |||
| 2511 | case BC_BNOT: | ||
| 2512 | #if LJ_HASFFI | ||
| 2513 | if (tref_iscdata(rc)) { | ||
| 2514 | rc = recff_bit64_bitop(J, rc, 0, rcv, NULL, IR_BNOT); | ||
| 2515 | break; | ||
| 2516 | } | ||
| 2517 | #endif | ||
| 2518 | rc = lj_opt_narrow_tobit(J, rc); | ||
| 2519 | rc = emitir(IRTI(IR_BNOT), rc, 0); | ||
| 2520 | break; | ||
| 2521 | |||
| 2522 | case BC_BAND: case BC_BOR: case BC_BXOR: | ||
| 2523 | #if LJ_HASFFI | ||
| 2524 | if (tref_iscdata(rb) || tref_iscdata(rc)) { | ||
| 2525 | rc = recff_bit64_bitop(J, rb, rc, rbv, rcv, (int)op - (int)BC_BAND + (int)IR_BAND); | ||
| 2526 | break; | ||
| 2527 | } | ||
| 2528 | #endif | ||
| 2529 | recbit: | ||
| 2530 | rb = lj_opt_narrow_tobit(J, rb); | ||
| 2531 | rc = lj_opt_narrow_tobit(J, rc); | ||
| 2532 | rc = emitir(IRTI((int)op - (int)BC_BAND + (int)IR_BAND), rb, rc); | ||
| 2533 | break; | ||
| 2534 | |||
| 2535 | case BC_BSHL: case BC_BSHR: case BC_BSAR: | ||
| 2536 | #if LJ_HASFFI | ||
| 2537 | { | ||
| 2538 | TRef xrb = rb, xrc = rc; | ||
| 2539 | if (recff_bit64_shift(J, &xrb, &xrc, rbv, rcv, (int)op - (int)BC_BSHL + (int)IR_BSHL)) { | ||
| 2540 | rc = xrb; | ||
| 2541 | break; | ||
| 2542 | } | ||
| 2543 | rc = xrc; /* Shift amount may have been converted. */ | ||
| 2544 | } | ||
| 2545 | #endif | ||
| 2546 | goto recbit; | ||
| 2547 | |||
| 2508 | /* -- Miscellaneous ops ------------------------------------------------- */ | 2548 | /* -- Miscellaneous ops ------------------------------------------------- */ |
| 2509 | 2549 | ||
| 2510 | case BC_CAT: | 2550 | case BC_CAT: |
diff --git a/src/vm_arm.dasc b/src/vm_arm.dasc index d67dbffcc..d9b2bf663 100644 --- a/src/vm_arm.dasc +++ b/src/vm_arm.dasc | |||
| @@ -849,6 +849,26 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 849 | | b ->vmeta_binop // Binop call for compatibility. | 849 | | b ->vmeta_binop // Binop call for compatibility. |
| 850 | #endif | 850 | #endif |
| 851 | | | 851 | | |
| 852 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 853 | | | ||
| 854 | |->vmeta_bnot: | ||
| 855 | | add CARG3, BASE, RC | ||
| 856 | | mov CARG4, CARG3 | ||
| 857 | | b >1 | ||
| 858 | | | ||
| 859 | |->vmeta_bitop: | ||
| 860 | | add CARG3, BASE, RB | ||
| 861 | | add CARG4, BASE, RC | ||
| 862 | |1: | ||
| 863 | | decode_OP OP, INS | ||
| 864 | | add CARG2, BASE, RA | ||
| 865 | | str BASE, L->base | ||
| 866 | | mov CARG1, L | ||
| 867 | | str PC, SAVE_PC | ||
| 868 | | str OP, ARG5 | ||
| 869 | | bl extern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 870 | | b ->cont_nop | ||
| 871 | | | ||
| 852 | |//-- Call metamethod ---------------------------------------------------- | 872 | |//-- Call metamethod ---------------------------------------------------- |
| 853 | | | 873 | | |
| 854 | |->vmeta_call: // Resolve and call __call metamethod. | 874 | |->vmeta_call: // Resolve and call __call metamethod. |
| @@ -3376,6 +3396,61 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 3376 | | ins_next3 | 3396 | | ins_next3 |
| 3377 | break; | 3397 | break; |
| 3378 | 3398 | ||
| 3399 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 3400 | |||
| 3401 | case BC_BNOT: | ||
| 3402 | | // RA = dst, RC = src | ||
| 3403 | | lsl RC, RC, #3 | ||
| 3404 | | ldrd CARG12, [BASE, RC] | ||
| 3405 | | checktp CARG1, LJ_TISNUM | ||
| 3406 | | bne ->vmeta_bnot | ||
| 3407 | | mvn CARG1, CARG1 | ||
| 3408 | | mvn CARG2, #~LJ_TISNUM | ||
| 3409 | | ins_next1 | ||
| 3410 | | ins_next2 | ||
| 3411 | | strd CARG12, [BASE, RA] | ||
| 3412 | | ins_next3 | ||
| 3413 | break; | ||
| 3414 | |||
| 3415 | |.macro ins_bitop, ins, shop | ||
| 3416 | | decode_RB8 RB, INS | ||
| 3417 | | decode_RC8 RC, INS | ||
| 3418 | | // RA = dst*8, RB = src1*8, RC = src2*8 | ||
| 3419 | | ldrd CARG12, [BASE, RB] | ||
| 3420 | | ldrd CARG34, [BASE, RC] | ||
| 3421 | | checktp CARG2, LJ_TISNUM | ||
| 3422 | | checktpeq CARG4, LJ_TISNUM | ||
| 3423 | | bne ->vmeta_bitop | ||
| 3424 | |.if shop == 1 | ||
| 3425 | | and CARG3, CARG3, #31 | ||
| 3426 | |.endif | ||
| 3427 | | ins CARG1, CARG1, CARG3 | ||
| 3428 | | mvn CARG2, #~LJ_TISNUM | ||
| 3429 | | ins_next1 | ||
| 3430 | | ins_next2 | ||
| 3431 | | strd CARG12, [BASE, RA] | ||
| 3432 | | ins_next3 | ||
| 3433 | |.endmacro | ||
| 3434 | |||
| 3435 | case BC_BAND: | ||
| 3436 | | ins_bitop and, 0 | ||
| 3437 | break; | ||
| 3438 | case BC_BOR: | ||
| 3439 | | ins_bitop orr, 0 | ||
| 3440 | break; | ||
| 3441 | case BC_BXOR: | ||
| 3442 | | ins_bitop eor, 0 | ||
| 3443 | break; | ||
| 3444 | case BC_BSHL: | ||
| 3445 | | ins_bitop lsl, 1 | ||
| 3446 | break; | ||
| 3447 | case BC_BSHR: | ||
| 3448 | | ins_bitop lsr, 1 | ||
| 3449 | break; | ||
| 3450 | case BC_BSAR: | ||
| 3451 | | ins_bitop asr, 1 | ||
| 3452 | break; | ||
| 3453 | |||
| 3379 | /* -- Constant ops ------------------------------------------------------ */ | 3454 | /* -- Constant ops ------------------------------------------------------ */ |
| 3380 | 3455 | ||
| 3381 | case BC_KSTR: | 3456 | case BC_KSTR: |
diff --git a/src/vm_arm64.dasc b/src/vm_arm64.dasc index be8b76a7a..60452fe56 100644 --- a/src/vm_arm64.dasc +++ b/src/vm_arm64.dasc | |||
| @@ -921,6 +921,25 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 921 | | b ->vmeta_binop // Binop call for compatibility. | 921 | | b ->vmeta_binop // Binop call for compatibility. |
| 922 | #endif | 922 | #endif |
| 923 | | | 923 | | |
| 924 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 925 | | | ||
| 926 | |->vmeta_bnot: | ||
| 927 | | add CARG3, BASE, RC, lsl #3 | ||
| 928 | | mov CARG4, CARG3 | ||
| 929 | | b >1 | ||
| 930 | | | ||
| 931 | |->vmeta_bitop: | ||
| 932 | | add CARG3, BASE, RB, lsl #3 | ||
| 933 | | add CARG4, BASE, RC, lsl #3 | ||
| 934 | |1: | ||
| 935 | | uxtb CARG5w, INSw | ||
| 936 | | add CARG2, BASE, RA, lsl #3 | ||
| 937 | | str BASE, L->base | ||
| 938 | | mov CARG1, L | ||
| 939 | | str PC, SAVE_PC | ||
| 940 | | bl extern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 941 | | b ->cont_nop | ||
| 942 | | | ||
| 924 | |//-- Call metamethod ---------------------------------------------------- | 943 | |//-- Call metamethod ---------------------------------------------------- |
| 925 | | | 944 | | |
| 926 | |->vmeta_call: // Resolve and call __call metamethod. | 945 | |->vmeta_call: // Resolve and call __call metamethod. |
| @@ -2878,6 +2897,51 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 2878 | | ins_next | 2897 | | ins_next |
| 2879 | break; | 2898 | break; |
| 2880 | 2899 | ||
| 2900 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 2901 | |||
| 2902 | case BC_BNOT: | ||
| 2903 | | // RA = dst, RC = src | ||
| 2904 | | ldr CARG1, [BASE, RC, lsl #3] | ||
| 2905 | | checkint CARG1, ->vmeta_bnot | ||
| 2906 | | mvn CARG1w, CARG1w | ||
| 2907 | | add_TISNUM CARG1, CARG1 | ||
| 2908 | | str CARG1, [BASE, RA, lsl #3] | ||
| 2909 | | ins_next | ||
| 2910 | break; | ||
| 2911 | |||
| 2912 | |.macro ins_bitop, ins | ||
| 2913 | | decode_RB RB, INS | ||
| 2914 | | and RC, RC, #255 | ||
| 2915 | | // RA = dst, RB = src1, RC = src2 | ||
| 2916 | | ldr CARG1, [BASE, RB, lsl #3] | ||
| 2917 | | ldr CARG2, [BASE, RC, lsl #3] | ||
| 2918 | | checkint CARG1, ->vmeta_bitop | ||
| 2919 | | checkint CARG2, ->vmeta_bitop | ||
| 2920 | | ins CARG1w, CARG1w, CARG2w | ||
| 2921 | | add_TISNUM CARG1, CARG1 | ||
| 2922 | | str CARG1, [BASE, RA, lsl #3] | ||
| 2923 | | ins_next | ||
| 2924 | |.endmacro | ||
| 2925 | |||
| 2926 | case BC_BAND: | ||
| 2927 | | ins_bitop and | ||
| 2928 | break; | ||
| 2929 | case BC_BOR: | ||
| 2930 | | ins_bitop orr | ||
| 2931 | break; | ||
| 2932 | case BC_BXOR: | ||
| 2933 | | ins_bitop eor | ||
| 2934 | break; | ||
| 2935 | case BC_BSHL: | ||
| 2936 | | ins_bitop lsl | ||
| 2937 | break; | ||
| 2938 | case BC_BSHR: | ||
| 2939 | | ins_bitop lsr | ||
| 2940 | break; | ||
| 2941 | case BC_BSAR: | ||
| 2942 | | ins_bitop asr | ||
| 2943 | break; | ||
| 2944 | |||
| 2881 | /* -- Constant ops ------------------------------------------------------ */ | 2945 | /* -- Constant ops ------------------------------------------------------ */ |
| 2882 | 2946 | ||
| 2883 | case BC_KSTR: | 2947 | case BC_KSTR: |
diff --git a/src/vm_mips.dasc b/src/vm_mips.dasc index 9a39edd69..40e15e888 100644 --- a/src/vm_mips.dasc +++ b/src/vm_mips.dasc | |||
| @@ -982,6 +982,25 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 982 | |. nop | 982 | |. nop |
| 983 | #endif | 983 | #endif |
| 984 | | | 984 | | |
| 985 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 986 | | | ||
| 987 | |->vmeta_bnot: | ||
| 988 | | move RC, RB | ||
| 989 | | | ||
| 990 | |->vmeta_bitop: | ||
| 991 | | load_got lj_meta_bitop | ||
| 992 | | decode_OP1 TMP0, INS | ||
| 993 | | sw BASE, L->base | ||
| 994 | | move CARG2, RA | ||
| 995 | | sw PC, SAVE_PC | ||
| 996 | | move CARG3, RB | ||
| 997 | | move CARG4, RC | ||
| 998 | | sw TMP0, ARG5 | ||
| 999 | | call_intern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 1000 | |. move CARG1, L | ||
| 1001 | | b ->cont_nop | ||
| 1002 | |. nop | ||
| 1003 | | | ||
| 985 | |//-- Call metamethod ---------------------------------------------------- | 1004 | |//-- Call metamethod ---------------------------------------------------- |
| 986 | | | 1005 | | |
| 987 | |->vmeta_call: // Resolve and call __call metamethod. | 1006 | |->vmeta_call: // Resolve and call __call metamethod. |
| @@ -3886,6 +3905,62 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 3886 | | ins_next2 | 3905 | | ins_next2 |
| 3887 | break; | 3906 | break; |
| 3888 | 3907 | ||
| 3908 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 3909 | |||
| 3910 | case BC_BNOT: | ||
| 3911 | | // RA = dst*8, RD = src*8 | ||
| 3912 | | addu RB, BASE, RD | ||
| 3913 | | lw TMP0, HI(RB) | ||
| 3914 | | lw CRET1, LO(RB) | ||
| 3915 | | bne TMP0, TISNUM, ->vmeta_bnot | ||
| 3916 | |. addu RA, BASE, RA | ||
| 3917 | | not CRET1, CRET1 | ||
| 3918 | | ins_next1 | ||
| 3919 | | sw TISNUM, HI(RA) | ||
| 3920 | | sw CRET1, LO(RA) | ||
| 3921 | | ins_next2 | ||
| 3922 | break; | ||
| 3923 | |||
| 3924 | |.macro ins_bitop, ins | ||
| 3925 | | // RA = dst*8, RB = src1*8, RC = src2*8 | ||
| 3926 | | decode_RB8a RB, INS | ||
| 3927 | | decode_RB8b RB | ||
| 3928 | | decode_RDtoRC8 RC, RD | ||
| 3929 | | addu RB, BASE, RB | ||
| 3930 | | addu RC, BASE, RC | ||
| 3931 | | lw TMP0, HI(RB) | ||
| 3932 | | lw TMP1, HI(RC) | ||
| 3933 | | lw CRET1, LO(RB) | ||
| 3934 | | bne TMP0, TISNUM, ->vmeta_bitop | ||
| 3935 | |. addu RA, BASE, RA | ||
| 3936 | | lw CRET2, LO(RC) | ||
| 3937 | | bne TMP1, TISNUM, ->vmeta_bitop | ||
| 3938 | |. ins CRET1, CRET1, CRET2 | ||
| 3939 | | ins_next1 | ||
| 3940 | | sw TISNUM, HI(RA) | ||
| 3941 | | sw CRET1, LO(RA) | ||
| 3942 | | ins_next2 | ||
| 3943 | |.endmacro | ||
| 3944 | |||
| 3945 | case BC_BAND: | ||
| 3946 | | ins_bitop and | ||
| 3947 | break; | ||
| 3948 | case BC_BOR: | ||
| 3949 | | ins_bitop or | ||
| 3950 | break; | ||
| 3951 | case BC_BXOR: | ||
| 3952 | | ins_bitop xor | ||
| 3953 | break; | ||
| 3954 | case BC_BSHL: | ||
| 3955 | | ins_bitop sllv | ||
| 3956 | break; | ||
| 3957 | case BC_BSHR: | ||
| 3958 | | ins_bitop srlv | ||
| 3959 | break; | ||
| 3960 | case BC_BSAR: | ||
| 3961 | | ins_bitop srav | ||
| 3962 | break; | ||
| 3963 | |||
| 3889 | /* -- Constant ops ------------------------------------------------------ */ | 3964 | /* -- Constant ops ------------------------------------------------------ */ |
| 3890 | 3965 | ||
| 3891 | case BC_KSTR: | 3966 | case BC_KSTR: |
diff --git a/src/vm_mips64.dasc b/src/vm_mips64.dasc index 41587e14d..e4a710b4a 100644 --- a/src/vm_mips64.dasc +++ b/src/vm_mips64.dasc | |||
| @@ -1028,6 +1028,24 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 1028 | |. nop | 1028 | |. nop |
| 1029 | #endif | 1029 | #endif |
| 1030 | | | 1030 | | |
| 1031 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 1032 | | | ||
| 1033 | |->vmeta_bnot: | ||
| 1034 | | move RC, RB | ||
| 1035 | | | ||
| 1036 | |->vmeta_bitop: | ||
| 1037 | | load_got lj_meta_bitop | ||
| 1038 | | sd BASE, L->base | ||
| 1039 | | move CARG2, RA | ||
| 1040 | | sd PC, SAVE_PC | ||
| 1041 | | move CARG3, RB | ||
| 1042 | | move CARG4, RC | ||
| 1043 | | decode_OP1 CARG5, INS // CARG5 == RB. | ||
| 1044 | | call_intern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 1045 | |. move CARG1, L | ||
| 1046 | | b ->cont_nop | ||
| 1047 | |. nop | ||
| 1048 | | | ||
| 1031 | |//-- Call metamethod ---------------------------------------------------- | 1049 | |//-- Call metamethod ---------------------------------------------------- |
| 1032 | | | 1050 | | |
| 1033 | |->vmeta_call: // Resolve and call __call metamethod. | 1051 | |->vmeta_call: // Resolve and call __call metamethod. |
| @@ -4113,6 +4131,65 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 4113 | | ins_next2 | 4131 | | ins_next2 |
| 4114 | break; | 4132 | break; |
| 4115 | 4133 | ||
| 4134 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 4135 | |||
| 4136 | case BC_BNOT: | ||
| 4137 | | // RA = dst*8, RD = src*8 | ||
| 4138 | | daddu RB, BASE, RD | ||
| 4139 | | ld CRET1, 0(RB) | ||
| 4140 | | gettp TMP0, CRET1 | ||
| 4141 | | bne TMP0, TISNUM, ->vmeta_bnot | ||
| 4142 | |. daddu RA, BASE, RA | ||
| 4143 | | not CRET1, CRET1 | ||
| 4144 | | zextw CRET1, CRET1 | ||
| 4145 | | settp CRET1, TISNUM | ||
| 4146 | | ins_next1 | ||
| 4147 | | sd CRET1, 0(RA) | ||
| 4148 | | ins_next2 | ||
| 4149 | break; | ||
| 4150 | |||
| 4151 | |.macro ins_bitop, ins | ||
| 4152 | | // RA = dst*8, RB = table*8, RC = key*8 | ||
| 4153 | | decode_RB8a RB, INS | ||
| 4154 | | decode_RB8b RB | ||
| 4155 | | decode_RDtoRC8 RC, RD | ||
| 4156 | | daddu RB, BASE, RB | ||
| 4157 | | daddu RC, BASE, RC | ||
| 4158 | | ld CRET1, 0(RB) | ||
| 4159 | | ld CRET2, 0(RC) | ||
| 4160 | | gettp TMP0, CRET1 | ||
| 4161 | | daddu RA, BASE, RA | ||
| 4162 | | bne TMP0, TISNUM, ->vmeta_bitop | ||
| 4163 | |. gettp TMP1, CRET2 | ||
| 4164 | | sextw CRET1, CRET1 | ||
| 4165 | | bne TMP1, TISNUM, ->vmeta_bitop | ||
| 4166 | |. ins CRET1, CRET1, CRET2 | ||
| 4167 | | zextw CRET1, CRET1 | ||
| 4168 | | settp CRET1, TISNUM | ||
| 4169 | | ins_next1 | ||
| 4170 | | sd CRET1, 0(RA) | ||
| 4171 | | ins_next2 | ||
| 4172 | |.endmacro | ||
| 4173 | |||
| 4174 | case BC_BAND: | ||
| 4175 | | ins_bitop and | ||
| 4176 | break; | ||
| 4177 | case BC_BOR: | ||
| 4178 | | ins_bitop or | ||
| 4179 | break; | ||
| 4180 | case BC_BXOR: | ||
| 4181 | | ins_bitop xor | ||
| 4182 | break; | ||
| 4183 | case BC_BSHL: | ||
| 4184 | | ins_bitop sllv | ||
| 4185 | break; | ||
| 4186 | case BC_BSHR: | ||
| 4187 | | ins_bitop srlv | ||
| 4188 | break; | ||
| 4189 | case BC_BSAR: | ||
| 4190 | | ins_bitop srav | ||
| 4191 | break; | ||
| 4192 | |||
| 4116 | /* -- Constant ops ------------------------------------------------------ */ | 4193 | /* -- Constant ops ------------------------------------------------------ */ |
| 4117 | 4194 | ||
| 4118 | case BC_KSTR: | 4195 | case BC_KSTR: |
diff --git a/src/vm_ppc.dasc b/src/vm_ppc.dasc index 440bf1c4b..8d257fdf5 100644 --- a/src/vm_ppc.dasc +++ b/src/vm_ppc.dasc | |||
| @@ -1269,6 +1269,25 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 1269 | | b ->vmeta_binop // Binop call for compatibility. | 1269 | | b ->vmeta_binop // Binop call for compatibility. |
| 1270 | #endif | 1270 | #endif |
| 1271 | | | 1271 | | |
| 1272 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 1273 | | | ||
| 1274 | |->vmeta_bnot: | ||
| 1275 | | mr CARG3, RD | ||
| 1276 | | mr CARG4, RD | ||
| 1277 | | b >1 | ||
| 1278 | | | ||
| 1279 | |->vmeta_bitop: | ||
| 1280 | | mr CARG3, RB | ||
| 1281 | | mr CARG4, RC | ||
| 1282 | |1: | ||
| 1283 | | add CARG2, BASE, RA | ||
| 1284 | | stp BASE, L->base | ||
| 1285 | | mr CARG1, L | ||
| 1286 | | stw PC, SAVE_PC | ||
| 1287 | | decode_OP1 CARG5, INS // Caveat: CARG5 overlaps INS. | ||
| 1288 | | bl extern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 1289 | | b ->cont_nop | ||
| 1290 | | | ||
| 1272 | |//-- Call metamethod ---------------------------------------------------- | 1291 | |//-- Call metamethod ---------------------------------------------------- |
| 1273 | | | 1292 | | |
| 1274 | |->vmeta_call: // Resolve and call __call metamethod. | 1293 | |->vmeta_call: // Resolve and call __call metamethod. |
| @@ -4357,6 +4376,87 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 4357 | | ins_next2 | 4376 | | ins_next2 |
| 4358 | break; | 4377 | break; |
| 4359 | 4378 | ||
| 4379 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 4380 | |||
| 4381 | case BC_BNOT: | ||
| 4382 | | lwzux CARG1, RD, BASE | ||
| 4383 | |.if DUALNUM | ||
| 4384 | | lwz CARG2, 4(RD) | ||
| 4385 | | checknum cr0, CARG1 | ||
| 4386 | | bne ->vmeta_bnot | ||
| 4387 | |.else | ||
| 4388 | | lfd FARG1, 0(RD) | ||
| 4389 | | checknum cr0, CARG1 | ||
| 4390 | | bge ->vmeta_bnot | ||
| 4391 | | fadd FARG1, FARG1, TOBIT | ||
| 4392 | | stfd FARG1, TMPD | ||
| 4393 | | lwz CARG2, TMPD_LO | ||
| 4394 | |.endif | ||
| 4395 | | not CARG2, CARG2 | ||
| 4396 | |7: | ||
| 4397 | |.if DUALNUM | ||
| 4398 | | ins_next1 | ||
| 4399 | | stwux TISNUM, RA, BASE | ||
| 4400 | | stw CARG2, 4(RA) | ||
| 4401 | |.else | ||
| 4402 | | tonum_u FARG1, CARG2 | ||
| 4403 | | ins_next1 | ||
| 4404 | | stfdx FARG1, BASE, RA | ||
| 4405 | |.endif | ||
| 4406 | | ins_next2 | ||
| 4407 | break; | ||
| 4408 | |||
| 4409 | |.macro ins_bitop, ins, shmod | ||
| 4410 | | // RA = dst*8, RB = src1*8, RC = src2*8 | ||
| 4411 | | lwzux CARG1, RB, BASE | ||
| 4412 | | lwzux CARG3, RC, BASE | ||
| 4413 | |.if DUALNUM | ||
| 4414 | | lwz CARG2, 4(RB) | ||
| 4415 | | lwz CARG4, 4(RC) | ||
| 4416 | | checknum cr0, CARG1 | ||
| 4417 | | checknum cr1, CARG3 | ||
| 4418 | | bne ->vmeta_bitop | ||
| 4419 | | bne cr1, ->vmeta_bitop | ||
| 4420 | |.else | ||
| 4421 | | lfd FARG1, 0(RB) | ||
| 4422 | | lfd FARG2, 0(RC) | ||
| 4423 | | checknum cr0, CARG1 | ||
| 4424 | | checknum cr1, CARG3 | ||
| 4425 | | bge ->vmeta_bitop | ||
| 4426 | | bge cr1, ->vmeta_bitop | ||
| 4427 | | fadd FARG1, FARG1, TOBIT | ||
| 4428 | | fadd FARG2, FARG2, TOBIT | ||
| 4429 | | stfd FARG1, TMPD | ||
| 4430 | | lwz CARG2, TMPD_LO | ||
| 4431 | | stfd FARG2, TMPD | ||
| 4432 | | lwz CARG4, TMPD_LO | ||
| 4433 | |.endif | ||
| 4434 | |.if shmod == 1 | ||
| 4435 | | rlwinm CARG4, CARG4, 0, 27, 31 | ||
| 4436 | |.endif | ||
| 4437 | | ins CARG2, CARG2, CARG4 | ||
| 4438 | | b <7 | ||
| 4439 | |.endmacro | ||
| 4440 | |||
| 4441 | case BC_BAND: | ||
| 4442 | | ins_bitop and, 0 | ||
| 4443 | break; | ||
| 4444 | case BC_BOR: | ||
| 4445 | | ins_bitop or, 0 | ||
| 4446 | break; | ||
| 4447 | case BC_BXOR: | ||
| 4448 | | ins_bitop xor, 0 | ||
| 4449 | break; | ||
| 4450 | case BC_BSHL: | ||
| 4451 | | ins_bitop slw, 1 | ||
| 4452 | break; | ||
| 4453 | case BC_BSHR: | ||
| 4454 | | ins_bitop srw, 1 | ||
| 4455 | break; | ||
| 4456 | case BC_BSAR: | ||
| 4457 | | ins_bitop sraw, 1 | ||
| 4458 | break; | ||
| 4459 | |||
| 4360 | /* -- Constant ops ------------------------------------------------------ */ | 4460 | /* -- Constant ops ------------------------------------------------------ */ |
| 4361 | 4461 | ||
| 4362 | case BC_KSTR: | 4462 | case BC_KSTR: |
diff --git a/src/vm_x64.dasc b/src/vm_x64.dasc index 16af1f299..5769d1cf5 100644 --- a/src/vm_x64.dasc +++ b/src/vm_x64.dasc | |||
| @@ -1093,6 +1093,47 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 1093 | | jmp ->vmeta_binop // Binop call for compatibility. | 1093 | | jmp ->vmeta_binop // Binop call for compatibility. |
| 1094 | #endif | 1094 | #endif |
| 1095 | | | 1095 | | |
| 1096 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 1097 | | | ||
| 1098 | |->vmeta_bnot: | ||
| 1099 | | mov RB, RA | ||
| 1100 | | lea RC, [BASE+RD*8] | ||
| 1101 | | mov RA, RC | ||
| 1102 | | jmp >2 | ||
| 1103 | | | ||
| 1104 | |// Caveat: ra=RB rb=RC rc=RA. | ||
| 1105 | |->vmeta_bitop: | ||
| 1106 | |.if DUALNUM | ||
| 1107 | | movzx RCd, PC_RB | ||
| 1108 | | movzx RAd, PC_RC | ||
| 1109 | |.endif | ||
| 1110 | | lea RC, [BASE+RC*8] | ||
| 1111 | | lea RA, [BASE+RA*8] | ||
| 1112 | |2: | ||
| 1113 | |.if X64WIN | ||
| 1114 | | mov CARG3, RC | ||
| 1115 | | mov CARG4, RA | ||
| 1116 | | lea RA, [BASE+RB*8] | ||
| 1117 | | movzx RC, PC_OP | ||
| 1118 | | mov ARG5, RC | ||
| 1119 | | mov L:RB, SAVE_L | ||
| 1120 | | mov L:RB->base, BASE // Caveat: CARG2d == BASE. | ||
| 1121 | | mov CARG2, RA | ||
| 1122 | | mov CARG1, L:RB // Caveat: CARG1d == RA. | ||
| 1123 | |.else | ||
| 1124 | | lea CARG2, [BASE+RB*8] | ||
| 1125 | | // CARG4 == RA. | ||
| 1126 | | movzx CARG5, PC_OP | ||
| 1127 | | mov L:CARG1, SAVE_L | ||
| 1128 | | mov L:CARG1->base, BASE // Caveat: CARG3d == BASE. | ||
| 1129 | | mov CARG3, RC | ||
| 1130 | | mov L:RB, L:CARG1 | ||
| 1131 | |.endif | ||
| 1132 | | mov SAVE_PC, PC | ||
| 1133 | | call extern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 1134 | | mov BASE, L:RB->base | ||
| 1135 | | jmp ->cont_nop | ||
| 1136 | | | ||
| 1096 | |//-- Call metamethod ---------------------------------------------------- | 1137 | |//-- Call metamethod ---------------------------------------------------- |
| 1097 | | | 1138 | | |
| 1098 | |->vmeta_call_ra: | 1139 | |->vmeta_call_ra: |
| @@ -3416,7 +3457,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 3416 | |.if DUALNUM | 3457 | |.if DUALNUM |
| 3417 | | ins_arithdn intins | 3458 | | ins_arithdn intins |
| 3418 | |.else | 3459 | |.else |
| 3419 | | ins_arith, sseins | 3460 | | ins_arith sseins |
| 3420 | |.endif | 3461 | |.endif |
| 3421 | |.endmacro | 3462 | |.endmacro |
| 3422 | 3463 | ||
| @@ -3476,6 +3517,88 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 3476 | | ins_next | 3517 | | ins_next |
| 3477 | break; | 3518 | break; |
| 3478 | 3519 | ||
| 3520 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 3521 | |||
| 3522 | case BC_BNOT: | ||
| 3523 | | ins_AD // RA = dst, RD = src | ||
| 3524 | |.if DUALNUM | ||
| 3525 | | mov RB, [BASE+RD*8] | ||
| 3526 | | checkint RB, ->vmeta_bnot | ||
| 3527 | | not RBd | ||
| 3528 | | setint RB | ||
| 3529 | | mov [BASE+RA*8], RB | ||
| 3530 | | ins_next | ||
| 3531 | |.else | ||
| 3532 | | checknumtp [BASE+RD*8], ->vmeta_bnot | ||
| 3533 | | movsd xmm0, qword [BASE+RD*8] | ||
| 3534 | | sseconst_tobit xmm1, RB | ||
| 3535 | | addsd xmm0, xmm1 | ||
| 3536 | | movd RBd, xmm0 | ||
| 3537 | | not RBd | ||
| 3538 | | cvtsi2sd xmm0, RBd | ||
| 3539 | | movsd qword [BASE+RA*8], xmm0 | ||
| 3540 | | ins_next | ||
| 3541 | |.endif | ||
| 3542 | break; | ||
| 3543 | |||
| 3544 | |.macro ins_bitop, ins, shift | ||
| 3545 | | ins_A // Really ins_ABC. RB = dst, RC = src1, RA = src2 | ||
| 3546 | | // Swap registers around to avoid reloading RA. | ||
| 3547 | | mov RB, RA | ||
| 3548 | | movzx RAd, RCL // Really src2 (C). | ||
| 3549 | | movzx RCd, RCH // Really src1 (B). | ||
| 3550 | |.if DUALNUM | ||
| 3551 | | mov RA, [BASE+RA*8] | ||
| 3552 | | mov RC, [BASE+RC*8] | ||
| 3553 | | checkint RA, ->vmeta_bitop | ||
| 3554 | | checkint RC, ->vmeta_bitop | ||
| 3555 | |.if shift == 1 | ||
| 3556 | | ins RCd, cl // Assumes RA is ecx. | ||
| 3557 | |.else | ||
| 3558 | | ins RCd, RAd | ||
| 3559 | |.endif | ||
| 3560 | | setint RC | ||
| 3561 | | mov [BASE+RB*8], RC | ||
| 3562 | |.else | ||
| 3563 | | checknumtp [BASE+RA*8], ->vmeta_bitop | ||
| 3564 | | checknumtp [BASE+RC*8], ->vmeta_bitop | ||
| 3565 | | movsd xmm0, qword [BASE+RA*8] | ||
| 3566 | | movsd xmm1, qword [BASE+RC*8] | ||
| 3567 | | sseconst_tobit xmm2, RC | ||
| 3568 | | addsd xmm0, xmm2 | ||
| 3569 | | addsd xmm1, xmm2 | ||
| 3570 | | movd RAd, xmm0 | ||
| 3571 | | movd RCd, xmm1 | ||
| 3572 | |.if shift == 1 | ||
| 3573 | | ins RCd, cl // Assumes RA is ecx. | ||
| 3574 | |.else | ||
| 3575 | | ins RCd, RAd | ||
| 3576 | |.endif | ||
| 3577 | | cvtsi2sd xmm0, RCd | ||
| 3578 | | movsd qword [BASE+RB*8], xmm0 | ||
| 3579 | |.endif | ||
| 3580 | | ins_next | ||
| 3581 | |.endmacro | ||
| 3582 | |||
| 3583 | case BC_BAND: | ||
| 3584 | | ins_bitop and, 0 | ||
| 3585 | break; | ||
| 3586 | case BC_BOR: | ||
| 3587 | | ins_bitop or, 0 | ||
| 3588 | break; | ||
| 3589 | case BC_BXOR: | ||
| 3590 | | ins_bitop xor, 0 | ||
| 3591 | break; | ||
| 3592 | case BC_BSHL: | ||
| 3593 | | ins_bitop shl, 1 | ||
| 3594 | break; | ||
| 3595 | case BC_BSHR: | ||
| 3596 | | ins_bitop shr, 1 | ||
| 3597 | break; | ||
| 3598 | case BC_BSAR: | ||
| 3599 | | ins_bitop sar, 1 | ||
| 3600 | break; | ||
| 3601 | |||
| 3479 | /* -- Constant ops ------------------------------------------------------ */ | 3602 | /* -- Constant ops ------------------------------------------------------ */ |
| 3480 | 3603 | ||
| 3481 | case BC_KSTR: | 3604 | case BC_KSTR: |
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc index 2c9386562..c930168ae 100644 --- a/src/vm_x86.dasc +++ b/src/vm_x86.dasc | |||
| @@ -1338,6 +1338,53 @@ static void build_subroutines(BuildCtx *ctx) | |||
| 1338 | | jmp ->vmeta_binop // Binop call for compatibility. | 1338 | | jmp ->vmeta_binop // Binop call for compatibility. |
| 1339 | #endif | 1339 | #endif |
| 1340 | | | 1340 | | |
| 1341 | |//-- Bit operator metamethods ------------------------------------------- | ||
| 1342 | | | ||
| 1343 | |->vmeta_bnot: | ||
| 1344 | | mov RB, RA | ||
| 1345 | | lea RC, [BASE+RD*8] | ||
| 1346 | | mov RA, RC | ||
| 1347 | | jmp >2 | ||
| 1348 | | | ||
| 1349 | |// Caveat: ra=RB rb=RC rc=RA. | ||
| 1350 | |->vmeta_bitop: | ||
| 1351 | | lea RC, [BASE+RC*8] | ||
| 1352 | | lea RA, [BASE+RA*8] | ||
| 1353 | |2: | ||
| 1354 | |.if X64WIN | ||
| 1355 | | mov CARG3d, RC | ||
| 1356 | | mov CARG4d, RA | ||
| 1357 | | lea RA, [BASE+RB*8] | ||
| 1358 | | movzx RC, PC_OP | ||
| 1359 | | mov ARG5d, RC | ||
| 1360 | | mov L:RB, SAVE_L | ||
| 1361 | | mov L:RB->base, BASE // Caveat: CARG2d == BASE. | ||
| 1362 | | mov CARG2d, RA | ||
| 1363 | | mov CARG1d, L:RB // Caveat: CARG1d == RA. | ||
| 1364 | |.elif X64 | ||
| 1365 | | lea CARG2, [BASE+RB*8] | ||
| 1366 | | // CARG4d == RA. | ||
| 1367 | | movzx CARG5d, PC_OP | ||
| 1368 | | mov L:CARG1d, SAVE_L | ||
| 1369 | | mov L:CARG1d->base, BASE // Caveat: CARG3d == BASE. | ||
| 1370 | | mov CARG3d, RC | ||
| 1371 | | mov L:RB, L:CARG1d | ||
| 1372 | |.else | ||
| 1373 | | lea RB, [BASE+RB*8] | ||
| 1374 | | mov ARG3, RC | ||
| 1375 | | movzx RC, PC_OP | ||
| 1376 | | mov ARG2, RB | ||
| 1377 | | mov L:RB, SAVE_L | ||
| 1378 | | mov ARG4, RA | ||
| 1379 | | mov ARG5, RC | ||
| 1380 | | mov ARG1, L:RB | ||
| 1381 | | mov L:RB->base, BASE | ||
| 1382 | |.endif | ||
| 1383 | | mov SAVE_PC, PC | ||
| 1384 | | call extern lj_meta_bitop // (lua_State *L, TValue *ra,*rb,*rc, BCReg op) | ||
| 1385 | | mov BASE, L:RB->base | ||
| 1386 | | jmp ->cont_nop | ||
| 1387 | | | ||
| 1341 | |//-- Call metamethod ---------------------------------------------------- | 1388 | |//-- Call metamethod ---------------------------------------------------- |
| 1342 | | | 1389 | | |
| 1343 | |->vmeta_call_ra: | 1390 | |->vmeta_call_ra: |
| @@ -4006,7 +4053,7 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 4006 | |.if DUALNUM | 4053 | |.if DUALNUM |
| 4007 | | ins_arithdn intins | 4054 | | ins_arithdn intins |
| 4008 | |.else | 4055 | |.else |
| 4009 | | ins_arith, sseins | 4056 | | ins_arith sseins |
| 4010 | |.endif | 4057 | |.endif |
| 4011 | |.endmacro | 4058 | |.endmacro |
| 4012 | 4059 | ||
| @@ -4092,6 +4139,89 @@ static void build_ins(BuildCtx *ctx, BCOp op, int defop) | |||
| 4092 | | ins_next | 4139 | | ins_next |
| 4093 | break; | 4140 | break; |
| 4094 | 4141 | ||
| 4142 | /* -- Bit ops ----------------------------------------------------------- */ | ||
| 4143 | |||
| 4144 | case BC_BNOT: | ||
| 4145 | | ins_AD // RA = dst, RD = src | ||
| 4146 | |.if DUALNUM | ||
| 4147 | | checkint RD, ->vmeta_bnot | ||
| 4148 | | mov RB, [BASE+RD*8] | ||
| 4149 | | not RB | ||
| 4150 | | mov dword [BASE+RA*8+4], LJ_TISNUM | ||
| 4151 | | mov dword [BASE+RA*8], RB | ||
| 4152 | | ins_next | ||
| 4153 | |.else | ||
| 4154 | | checknum RD, ->vmeta_bnot | ||
| 4155 | | movsd xmm0, qword [BASE+RD*8] | ||
| 4156 | | sseconst_tobit xmm1, RBa | ||
| 4157 | | addsd xmm0, xmm1 | ||
| 4158 | | movd RB, xmm0 | ||
| 4159 | | not RB | ||
| 4160 | | cvtsi2sd xmm0, RB | ||
| 4161 | | movsd qword [BASE+RA*8], xmm0 | ||
| 4162 | | ins_next | ||
| 4163 | |.endif | ||
| 4164 | break; | ||
| 4165 | |||
| 4166 | |.macro ins_bitop, ins, shift | ||
| 4167 | | ins_A // Really ins_ABC. RB = dst, RC = src1, RA = src2 | ||
| 4168 | | // Swap registers around to avoid reloading RA. | ||
| 4169 | | mov RB, RA | ||
| 4170 | | movzx RA, RCL // Really src2 (C). | ||
| 4171 | | movzx RC, RCH // Really src1 (B). | ||
| 4172 | |.if DUALNUM | ||
| 4173 | | checkint RA, ->vmeta_bitop | ||
| 4174 | | checkint RC, ->vmeta_bitop | ||
| 4175 | |.if shift == 1 | ||
| 4176 | | mov RA, [BASE+RA*8] | ||
| 4177 | | mov RC, [BASE+RC*8] | ||
| 4178 | | ins RC, cl // Assumes RA is ecx. | ||
| 4179 | |.else | ||
| 4180 | | mov RC, [BASE+RC*8] | ||
| 4181 | | ins RC, [BASE+RA*8] | ||
| 4182 | |.endif | ||
| 4183 | | mov dword [BASE+RB*8+4], LJ_TISNUM | ||
| 4184 | | mov dword [BASE+RB*8], RC | ||
| 4185 | |.else | ||
| 4186 | | checknum RA, ->vmeta_bitop | ||
| 4187 | | checknum RC, ->vmeta_bitop | ||
| 4188 | | movsd xmm0, qword [BASE+RA*8] | ||
| 4189 | | movsd xmm1, qword [BASE+RC*8] | ||
| 4190 | | sseconst_tobit xmm2, RCa | ||
| 4191 | | addsd xmm0, xmm2 | ||
| 4192 | | addsd xmm1, xmm2 | ||
| 4193 | | movd RA, xmm0 | ||
| 4194 | | movd RC, xmm1 | ||
| 4195 | |.if shift == 1 | ||
| 4196 | | ins RC, cl // Assumes RA is ecx. | ||
| 4197 | |.else | ||
| 4198 | | ins RC, RA | ||
| 4199 | |.endif | ||
| 4200 | | cvtsi2sd xmm0, RC | ||
| 4201 | | movsd qword [BASE+RB*8], xmm0 | ||
| 4202 | |.endif | ||
| 4203 | | ins_next | ||
| 4204 | |.endmacro | ||
| 4205 | |||
| 4206 | case BC_BAND: | ||
| 4207 | | ins_bitop and, 0 | ||
| 4208 | break; | ||
| 4209 | case BC_BOR: | ||
| 4210 | | ins_bitop or, 0 | ||
| 4211 | break; | ||
| 4212 | case BC_BXOR: | ||
| 4213 | | ins_bitop xor, 0 | ||
| 4214 | break; | ||
| 4215 | case BC_BSHL: | ||
| 4216 | | ins_bitop shl, 1 | ||
| 4217 | break; | ||
| 4218 | case BC_BSHR: | ||
| 4219 | | ins_bitop shr, 1 | ||
| 4220 | break; | ||
| 4221 | case BC_BSAR: | ||
| 4222 | | ins_bitop sar, 1 | ||
| 4223 | break; | ||
| 4224 | |||
| 4095 | /* -- Constant ops ------------------------------------------------------ */ | 4225 | /* -- Constant ops ------------------------------------------------------ */ |
| 4096 | 4226 | ||
| 4097 | case BC_KSTR: | 4227 | case BC_KSTR: |
